C++11之用户自定义字面量(ClassType operator““_C(param...))

系列文章

C++11之正则表达式(regex_match、regex_search、regex_replace)

C++11之线程库(Thread、Mutex、atomic、lock_guard、同步)

C++11之智能指针(unique_ptr、shared_ptr、weak_ptr、auto_ptr)浅谈内存管理

C++11之强制类型转换(static_cast,const_cast,dynamic_cast,reinterpret_cast)

C++11之Lanbda表达式(匿名函数)

C++11之右值引用:移动语义和完美转发(带你了解移动构造函数、纯右值、将亡值、右值引用、std::move、forward等新概念)

C++11之继承构造函数(using 声明)

C++11之委派构造函数

C++11之显式转换操作符-explicit

C++11之初始化列表

C++11之防止类型收窄(列表初始化)



用户自定义字面量

在实际的开发过程中,我们会经常使用到结构体来表示一个新的类型。那么在遇到结构体类型都数据进行运算时,只能先依次定义,然后进行运行。这在测试环节会非常的繁琐,为此C++11标准增加了可以通过后缀表示的操作符来将字面量转换为需要的类型。

场景案例

例如 我们现在需要使用一个颜色的结构体然后进行合并输出的一个操作,那么实现大概是下面这个样子:

#include <iostream>
#include <cstdlib>
using namespace std;

typedef unsigned char uint8;

struct RGBA
{
	uint8 r;
	uint8 g;
	uint8 b;
	uint8 a;
	RGBA(uint8 R, uint8 G, uint8 B, uint8 A = 0) :r(R),g(G),b(B),a(A){}
};

std::ostream& operator<< (std::ostream& out, RGBA& col)
{
	return out << "r: " << (int)col.r
		<< ", g: " << (int)col.g
		<< ", b: " << (int)col.b
		<< ", a: " << (int)col.a << endl;
}

void blend(RGBA& col1, RGBA& col2)
{
	cout << __func__ << endl << col1 << col2 << endl;
}

int main()
{

	RGBA col1(255, 255, 255); // C++98 初始化
	RGBA col2{ 10, 22, 65, 5 }; // C++11 初始化列表

	blend(col1, col2); // 进行运算
	return 0;
}

运行结果:

blend
r: 255, g: 255, b: 255, a: 0
r: 10, g: 22, b: 65, a: 5

很明显当我需要进行运算时,必须先依次对变量进行创建,能不能直接传常量到blend函数中呢?C++11就可以做到,后缀标识符配合右值引用完美解决这个问题。

C++11使用后缀标识符解析字符串

主要的改动就是需要添加下面这个函数,这个函数的主要功能就是通过解析标识符来定位对应的指针,然后将字符串转换为整型的一个思路。

RGBA operator""_C(const char* col, size_t n)
{
	const char* p = col;
	const char* end = col + n;
	const char* r, * g, * b, * a;
	r = g = b = a = nullptr;

	for (; p != end; ++p)
	{
		if(*p == 'r')
		{
			r = p;
		}
		else if(*p == 'g')
		{
			g = p;
		}
		else if(*p == 'b')
		{
			b = p;
		}
		else if(*p == 'a')
		{
			a = p;
		}
	}

	if(r == nullptr || g == nullptr || b == nullptr)
	{
		throw;
	}
	else if(a == nullptr)
	{
		return RGBA(atoi(r + 1), atoi(g + 1), atoi(b + 1));
	}
	else
	{
		return RGBA(atoi(r + 1), atoi(g + 1), atoi(b + 1), atoi(a + 1));
	}
}

然后因为我们需要输入字面常量,所以我们的blend函数的参数就需要将左值引用改成右值引用。

void blend(RGBA&& col1, RGBA&& col2)
{
	cout << __func__ << endl << col1 << col2 << endl;
}

在调用方面也从之前的三行压缩为一行,更加简洁、优雅。

int main()
{
	blend("r255 g240 b155"_C, "r15 g255 b10 a7"_C);

	return 0;
}

C++11使用后缀标识符解析数字

对应不同类型的字面量还有着相应的限制,就比如整型类型字面量的参数只能是unsigned long long 或者 const char*。我将在最后对各个类型的要求做一个总结。

#include <iostream>
#include <cstdlib>
using namespace std;


struct T
{
public:
	int t;
};

T operator""_t(unsigned long long t)
{
	return { static_cast<int>(t) };
}

int main()
{
	T t = 1111_t;
	return 0;
}

字面量规则

字面量类型参数要求说明
整型unsigned long long or const char*unsigned long long类型无法容纳下该字面量时,编译器会自动将字面量转换为以\0结束的字符串,并调用const char*参数版本的函数来处理
浮点型long double or const char*和整型的处理相同,long double 容纳不下时,编译器会自动将字面量转换为以\0结束的字符串,并调用const char*参数版本的函数来处理
字符串(const char*, size_t)只有一种写法
字符char只有一种写法

注意

  • 后缀建议以_下划线这种格式。
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这是上题的代码:def infix_to_postfix(expression): precedence = {'!': 3, '&': 2, '|': 1, '(': 0} op_stack = [] postfix_list = [] token_list = expression.split() for token in token_list: if token.isalnum(): postfix_list.append(token) elif token == '(': op_stack.append(token) elif token == ')': top_token = op_stack.pop() while top_token != '(': postfix_list.append(top_token) top_token = op_stack.pop() else: # operator while op_stack and precedence[op_stack[-1]] >= precedence[token]: postfix_list.append(op_stack.pop()) op_stack.append(token) while op_stack: postfix_list.append(op_stack.pop()) return ' '.join(postfix_list) class Node: def __init__(self, value): self.value = value self.left_child = None self.right_child = None def build_expression_tree(postfix_expr): operator_stack = [] token_list = postfix_expr.split() for token in token_list: if token.isalnum(): node = Node(token) operator_stack.append(node) else: right_node = operator_stack.pop() left_node = operator_stack.pop() node = Node(token) node.left_child = left_node node.right_child = right_node operator_stack.append(node) return operator_stack.pop() def evaluate_expression_tree(node, variable_values): if node.value.isalnum(): return variable_values[node.value] else: left_value = evaluate_expression_tree(node.left_child, variable_values) right_value = evaluate_expression_tree(node.right_child, variable_values) if node.value == '!': return not left_value elif node.value == '&': return left_value and right_value elif node.value == '|': return left_value or right_value expression = "!a & (b | c)" postfix_expression = infix_to_postfix(expression) expression_tree = build_expression_tree(postfix_expression) variable_values = {'a': True, 'b': False, 'c': True} result = evaluate_expression_tree(expression_tree, variable_values) print(result)
06-12

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林夕07

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值