11

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

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

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

4

2 回答 2

7

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

举个例子,看看这个。作为另一个显示constexprFDIS 允许的高级计算形式的示例,您可以使用编译时 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);
}

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

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

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

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

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

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

于 2011-04-16T03:23:46.850 回答
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

于 2012-12-22T15:23:26.057 回答