在探讨constexpr / operator“'C ++ 11的特性时,我偶然发现了这篇文章:http://www.codeproject.com/Articles/447922/Application-of-Cplusplus11-User-Defined-Literals-t
它举例说明了提供字符串到二进制数udl的代码如何:
constexpr unsigned long long ToBinary(unsigned long long x, const char* s)
{
return (!*s ? x : ToBinary(x + x + (*s =='1'? 1 : 0), s+1));
}
constexpr unsigned long long int operator "" _b(const char* s)
{ return ToBinary(0,s);}
这一切都像宣传的那样有效,但我不太喜欢全局命名空间被辅助ToBinary功能污染。我没有试图破坏函数的名称,而是试图设想一个解决方案,它将在运算符“”体内嵌入递归lambda函数。
C ++中的递归lambdas解决方案是已知的,它们使用std :: function用法。为了在constexpr运算符“”中实现这一点,需要在单个return语句中嵌入递归lambda的声明和调用。我尝试实现这一目标失败了,所以我求助于SO。是否可以在constexpr运算符中调用递归lambda?如果有,那有什么提示?
谢谢,
答案 0 :(得分:3)
根据[expr.const] / 2,明确禁止 lambda-expression 成为核心常量表达式的一部分。它可以出现在三元运算符的未评估操作数中,例如p ? 42 : [](){ return 255; }();
,如果p
评估为true
。
也就是说,lambda也可能出现在constexpr
函数中,但是,当函数用于常量表达式时,可能无法评估该部分。例如:
constexpr unsigned long long int operator "" _b(const char* s)
{
return *s == '0' || *s == 0 ? 0 : [=]() mutable
{
unsigned long long ret = 0;
for(; *s != 0; ++s)
{
ret <<= 1;
if(*s == '1') ret += 1;
}
return ret;
}();
}
#include <iostream>
int main()
{
constexpr int c = 0_b; // fine
//constexpr int c1 = 1_b; // error
std::cout << 1010_b << std::endl; // fine
}
当然,这不是很有用;运算符是constexpr
允许在常量表达式中将字符串解析为二进制文字。因此,执行此转换的运算符部分必须是有效(核心)常量表达式。
由于精确指定了运算符的签名,因此不能重复运算符本身并将处理后的数据作为附加参数传递。您也许不能在C ++ 11的constexpr
中使用循环。
当然,您可以使用命名空间。这对用户来说甚至可能更好:
namespace my_literals
{
constexpr unsigned long long ToBinary(unsigned long long x, const char* s)
{
return (!*s ? x : ToBinary(x + x + (*s =='1'? 1 : 0), s+1));
}
constexpr unsigned long long int operator "" _b(const char* s)
{ return ToBinary(0,s);}
}
// user writes:
using my_literals::operator ""_b;