【问题标题】:User defined literals definitions用户定义的文字定义
【发布时间】:2017-01-21 21:56:00
【问题描述】:

我在看cppreference page for user defined 字面量,我想除了几个例子之外我什么都懂

template <char...> double operator "" _π(); // OK

这个运算符是如何工作的?你怎么称呼它?

double operator"" _Z(long double); // error: all names that begin with underscore
                                   // followed by uppercase letter are reserved
double operator""_Z(long double); // OK: even though _Z is reserved ""_Z is allowed

以上两个函数有什么区别?如果第一个函数没有错误,调用第一个函数和第二个函数有什么区别?

谢谢!

【问题讨论】:

    标签: c++ c++11 user-defined-literals


    【解决方案1】:
    template <char...> double operator "" _π(); // OK
    

    这个运算符是如何工作的?你怎么称呼它?

    1.234_π 将调用operator "" _π&lt;'1', '.', '2', '3', '4'&gt;()。此表单允许您检测通常无法检测到的拼写差异(例如1.21.20),并允许您避免由于1.2 甚至在long double 中无法精确表示而导致的舍入问题。

    double operator"" _Z(long double); // error: all names that begin with underscore
                                       // followed by uppercase letter are reserved
    double operator""_Z(long double); // OK: even though _Z is reserved ""_Z is allowed
    

    以上两个功能有什么区别?

    C++ 标准根据tokens 定义语法,您可以将其解释为单词。 "" _Z 是两个令牌,""_Z""_Z 是单个令牌。

    这种区别很重要:给定#define S " world!",然后是"Hello" S,空格使S 成为独立标记,防止它被视为用户定义的文字后缀。

    为了更容易编码,在定义这些函数时通常允许使用"" _Z""_Z 语法,但"" _Z 语法要求将_Z 视为标识符。当实现将 _Z 预定义为宏或将其声明为自定义关键字时,这可能会导致问题。

    【讨论】:

    • 你知道为什么 文字,像这样的"something"_π 不调用operator "" _π&lt;'s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g'&gt;() 吗?如何更改该用户定义文字的声明以使这些字符作为模板参数传递?
    • @Curious 这是不可能的,将单个字符作为模板参数传递只能使用数字文字。
    • 知道为什么会这样吗?我不明白为什么不支持字符..
    • @Curious 我猜只是因为对于数字文字,可以找到模板形式有帮助的具体示例,而对于字符串和字符文字,则不然。
    • 看来你必须不走寻常路,不支持常规字符串文字。有没有其他方法可以实现这一点?
    【解决方案2】:

    据我了解,这两个签名没有区别。

    问题在于标识符_Z 在技术上被标准保留。主要区别在于有一个空格:

    double operator""/*space*/_Z(long double); 
    
    double operator""_Z(long double); 
    

    删除空格基本上是一种解决方法,理论上可以抑制错误(或更可能是警告)。

    就您如何使用它们而言,您是否查看了您列出的链接中的示例?

    #include <iostream>
    
    // used as conversion
    constexpr long double operator"" _deg ( long double deg )
    {
        return deg*3.141592/180;
    }
    
    // used with custom type
    struct mytype
    {
        mytype ( unsigned long long m):m(m){}
        unsigned long long m;
    };
    mytype operator"" _mytype ( unsigned long long n )
    {
        return mytype(n);
    }
    
    // used for side-effects
    void operator"" _print ( const char* str )
    {
        std::cout << str;
    }
    
    int main(){
        double x = 90.0_deg;
        std::cout << std::fixed << x << '\n';
        mytype y = 123_mytype;
        std::cout << y.m << '\n';
        0x123ABC_print;
    }
    

    用户定义文字背后的想法是允许创建一个可应用于内置类型的运算符,该类型可以将内置文字转换为另一种类型。

    编辑:

    要调用这些运算符之一,您只需将运算符作为后缀附加到值文字。所以给定:

    // used as conversion
    constexpr long double operator"" _deg ( long double deg )
    {
        return deg*3.141592/180;
    }
    

    调用代码例如:

    long double d = 45_deg;
    

    至于使用template &lt;char...&gt; double operator "" _π();也许看看this.

    【讨论】:

    • 我确实查看了链接中的示例,但我不明白两个 _Z 运算符有什么区别,如果 _Z 没有保留,那么你会怎么称呼它?这也是用户定义的文字吗?多余的空间是什么意思? 部分也没有得到答复。
    • 对不起,我认为我的问题并不清楚。关于_Z 这两个东西之间的区别,我想问的是空格到底是什么意思?我知道在通常情况下如何调用操作员,但是空格是什么意思?总是出错吗?
    • @Curious - 如果您足够接近地阅读cppreference,它说明""_Z(没有空格)是可以的,即使_Z 是保留的。它还表明,即使 if 是关键字,更具争议的 complex&lt;float&gt; 文字 ""if(同样没有空格)必须有效。
    • "基本上:运算符""_Z && 运算符"" _Z 是两个不同的标识符,后者是保留的。" ——啊?不,这是完全错误的。 operator""_Z 和 operator"" _Z,如果有效,将是完全相同的函数。用那个 operator"" _deg 自己试试看:添加一个 operator""_deg 看看你是否得到一个重新定义错误。 operator"" _Z 的问题在于,因为 _Z 是为实现使用而保留的,所以实现可以例如将其定义为扩展为您喜欢的任何内容的宏。 operator""_Z 避免了这个问题,因为 _Z 不是一个单独的标记,它是 ""_Z 标记的一部分。
    • _π(char...c)double d = 'c'_π; -- 抱歉,这显然只是猜测,你猜错了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 2017-12-26
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    相关资源
    最近更新 更多