【问题标题】:Are user-defined-literals resolved at compile-time or runtime?用户定义的文字是在编译时还是运行时解析的?
【发布时间】:2011-04-16 03:15:39
【问题描述】:

我想知道,因为像ULLf 等预定义的文字显然在编译时就已经解决了。标准(2.14.8 [lex.ext])似乎没有定义这一点,但它似乎倾向于运行时:

[2.14.8 / 2]
用户定义的文字被视为对文字运算符或文字运算符模板(13.5.8)的调用。到 使用 ud-suffix X(literal-operator-id)为给定的用户定义文字 L 确定此调用的形式 使用非限定名称规则在 L 的上下文中查找其文字后缀标识符为 X 查找(3.4.1)。令 S 是此查找找到的声明集。 S 不能为空。
(强调我的。)

但是,对我来说,这似乎引入了不必要的运行时开销,因为文字只能附加到编译时可用的值,例如 13.37f"hello"_x(其中 _x 是用户定义的-文字)。
然后,我们得到了模板化的用户定义文字,它从未真正在标准 AFAICS 中得到定义(即,没有给出示例,请证明我错了)。该函数是在编译时以某种方式神奇地调用,还是仍然在运行时?

【问题讨论】:

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


    【解决方案1】:

    是的,你得到一个函数调用。但是由于 constexpr 文字运算符函数,函数调用可以是编译时常量表达式。

    例如,请参阅this one。作为另一个展示 FDIS 允许的高级形式的 constexpr 计算的示例,您可以使用编译时 base-26 文字

    typedef unsigned long long ull;
    
    constexpr ull base26(char const *s, ull ps) {
      return (*s && !(*s >= 'a' && *s <= 'z')) ? throw "bad char!" :
        (!*s ? ps : base26(s + 1, (ps * 26ULL) + (*s - 'a')));
    }
    
    constexpr ull operator "" _26(char const *s, std::size_t len) {
      return base26(s, 0);
    }
    

    "bcd-"_26 将计算一个 throw 表达式,从而导致返回值变为非常量。反过来,它会导致将 "bcd-"_26 用作常量表达式的任何使用都变得格式错误,并且任何非常量使用都会在运行时抛出。允许的形式 "bcd"_26 计算为相应计算值的常量表达式。

    请注意,FDIS 并未明确允许从字符串字面量读取,但它没有问题并且 GCC 支持这一点(字符左值引用是一个常量表达式,并且字符的值在编译时是已知的)。 IMO 如果一个人眯着眼睛,就可以阅读 FDIS,就好像允许这样做一样。

    然后,我们得到了模板化的用户定义文字,它从未真正在标准 AFAICS 中得到定义(即,没有给出示例,请证明我错了)

    2.14.8 中定义了将文字视为调用文字运算符模板的处理。您可以在 13.5.8 中找到更多关于文字运算符函数/函数模板本身的详细信息。

    该函数是在编译时以某种方式神奇地调用,还是仍然在运行时?

    关键字是函数调用替换。见 7.1.5。

    【讨论】:

    • 谢谢,完全忘记了constexpr。 :) 也感谢那段。
    • 当你被告知长度时,寻找 NUL 终止似乎是可疑的。
    【解决方案2】:

    @Johannes S 当然是正确的,但我想清楚地补充一下(因为我遇到了这个问题),即使对于constexpr 用户定义的文字,parameters 也不被视为 constexpr 或编译时间常量,例如它们不能用作模板的整数常量。

    此外,只有这样的东西才会真正给出编译时评估:

    inline constexpr long long _xx(unsigned long long v) {
      return (v > 100 ) ? throw std::exception() : v; 
    }
    constexpr auto a= 150_xx;
    

    所以,这不会编译。但这会:

    cout << 150_xx << endl;
    

    以下是不允许的:

    inline constexpr long long _xx(unsigned long long v) {
      return some_trait<v>::value; 
    }
    

    这很烦人,但考虑到(其他)constexpr 函数也可以在执行期间调用,这很自然。

    只有对于整数用户定义的文字,才可以强制编译时处理,通过使用模板形式。我的问题和自我回答中的示例:https://stackoverflow.com/a/13869688/1149664

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-29
      • 2011-04-07
      • 1970-01-01
      • 2012-06-26
      • 1970-01-01
      • 2014-11-30
      • 2013-09-17
      • 2021-02-26
      相关资源
      最近更新 更多