constexpr运算符中的C ++ 11递归lambda函数“”

时间:2013-10-03 18:25:52

标签: c++11 recursion lambda constexpr user-defined-literals

在探讨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?如果有,那有什么提示?

谢谢,

1 个答案:

答案 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;