1

在探索 C++11 的 constexpr/operator"' 特性的主题时,我偶然发现了这篇文章: http: //www.codeproject.com/Articles/447922/Application-of-Cplusplus11-User-Defined-Literals-t

它引用了一个示例,说明提供 string-to-binary-number 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 函数污染。我没有尝试修改函数的名称,而是尝试构想一种解决方案,该解决方案将在 operator"" 主体中嵌入一个递归 lambda 函数。

C++ 中递归 lambda 的解决方案是已知的,它们采用 std::function 用法。为了在 constexpr 运算符“”中实现这一点,需要将递归 lambda 的声明和调用嵌入到单个 return 语句中。我实现这一目标的尝试失败了,所以我求助于 SO 寻求帮助。是否有可能在 constexpr 运算符“”中调用递归 lambda?如果有,有什么提示?

谢谢,

4

1 回答 1

3

根据 [expr.const]/2,明确禁止lambda 表达式成为核心常量表达式的一部分。它可以出现在三元运算符的未计算操作数中,例如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;
于 2013-10-03T20:22:44.563 回答