是否在编译时或运行时解析了用户定义的文字?

时间:2011-04-16 03:15:39

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

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

  

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

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

2 个答案:

答案 0 :(得分:7)

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

有关示例,请参阅this one。作为显示FDIS允许的constexpr计算的高级形式的另一个例子,你可以编译时间基数为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-expression,从而使返回值变为非常量。反过来,它导致任何使用"bcd-"_26作为常量表达式变得格式不正确,以及任何非常量用法在运行时抛出。允许的形式"bcd"_26求值为相应计算值的常量表达式。

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

  

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

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

  

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

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

答案 1 :(得分:0)

@Johannes S当然是正确的,但我想明确添加(因为我遇到了这个),即使是constexpr用户定义的文字,也不考虑参数 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