ssc*_*urr 18 c++ constexpr c++11
仅仅因为一个函数(或构造函数)......
...并不意味着编译器将在转换期间评估constexpr函数.我一直在查看C++ 11 FDIS(N3242,可从http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/获取)来尝试确定两件事:
第5.19节第1段说明在翻译过程中可以评估常量表达式.据我所知,第5.19节的其余部分阐述了constexpr函数定义中有效的规则.
我理解我可以通过将constexpr函数的结果声明为constexpr来强制转换期间的constexpr评估.像这样:
// Declaration
constexpr double eulers_num() { return 2.718281828459045235360287471; }
// Forced evaluation during translation
constexpr double twoEulers = eulers_num() * 2.0;
static_assert(twoEulers > 5.0, "Yipes!");
Run Code Online (Sandbox Code Playgroud)
到目前为止,我一直无法找到FDIS中的段落:
twoEulers在翻译过程中要评估的力量我对发现特别感兴趣的是翻译期间的constexpr评估是否由以下因素触发:
如果可能的话,请在您的回复中引用我可以查找的FDIS部分或我可以在FDIS中搜索的关键短语.标准中的英语有点迟钝,所以我可能已经阅读了相关的段落并完全忽略了它们的含义或意图.
constexpr只要实际可行,就可以"允许" 在编译时评估调用.请记住,规范在"as if"规则下运行.因此,如果您无法区分,编译器可以做任何想做的事情.
编译时需要编译器constexpr在编译时实际需要答案时评估调用.例如:
constexpr int foo() {return 5;}
std::array<float, foo()> arr;
Run Code Online (Sandbox Code Playgroud)
编译器需要在编译时知道数组大小.因此,它必须在编译时评估常量表达式.如果constexpr在编译时无法执行该函数,则会出现编译时错误.
通过梳理 FDIS,我发现了三个地方指定在翻译过程中必须对 constexpr 表达式求值的位置。
\n第 3.6.2 节非局部变量的初始化第 2 段表示,如果使用构造函数初始化具有静态或线程局部存储持续时间的对象constexpr,则在转换期间对构造函数进行求值:
\n\n执行常量初始化:
\n\n\n\n
\n- 如果具有静态或线程存储持续时间的对象由构造函数调用初始化,如果构造函数是构造函数
\nconstexpr,如果所有构造函数参数都是常量表达式(包括转换),并且如果在函数调用替换(7.1.5)之后,每个构造函数mem-initializers中的 call 和 full-expression是常量表达式;
第 7.1.5 节 constexpr 说明符,第 9 段表示,如果对象声明包含该constexpr说明符,则该对象在翻译期间被评估(即,是文字):
\n\nA
\nconstexpr将该对象声明为 const。这样的对象应具有文字类型并应进行初始化。如果它是由构造函数调用初始化的,则该调用应为常量表达式 (5.19)。否则,出现在其初始值设定项中的每个完整表达式都应是常量表达式。用于转换初始值设定项表达式的每个隐式转换和用于初始化的每个构造函数调用都应是常量表达式 (5.19) 中允许的转换之一。
我\xe2\x80\x99 听说人们认为这一段为实现将初始化推迟到运行时留出了空间,除非可以在翻译过程中检测到效果,例如,由于static_assert. 这可能不是一个准确的观点,因为在某些情况下,一个值是否在转换过程中被初始化是可以观察到的。第 5.19 节常量表达式第 4 段强化了这一观点:
\n\n[注意:虽然在某些情况下,常量表达式必须在程序翻译期间求值,但其他情况下也可以在程序执行期间求值。由于本国际标准对浮点运算的准确性没有限制,因此未指定翻译过程中浮点表达式的求值是否与相同表达式(或对相同值的相同运算)的求值产生相同的结果) 在程序执行期间... \xe2\x80\x94尾注]
\n
第 9.4.2 节静态数据成员第 3 段表示,如果文字类型的 const 静态数据成员由 constexpr 函数或构造函数初始化,则必须在翻译期间评估该函数或构造函数:
\n\n\n如果静态数据成员是 const 文字类型,则其在类定义中的声明可以指定大括号或等于初始化程序,其中作为赋值表达式的每个初始化程序子句都是常量表达式。可以在类定义中使用说明符声明文字类型的静态数据成员;如果是这样,其声明应指定一个大括号或等于初始化程序,其中作为赋值表达式的每个初始化程序子句都是常量表达式。[注意:在这两种情况下,成员都可能出现在常量表达式中。\xe2\x80\x94尾注]
\nconstexpr
有趣的是,我在 FDIS 中没有发现任何需要在constexpr其结果用作数组维度时计算表达式的内容。我非常确定标准委员会希望情况如此。但我也可能在搜索中错过了这一点。
除了这些情况之外,C++11 标准允许在翻译期间执行 constexpr 函数和构造函数中的计算。但它并不需要它。计算可以在运行时发生。编译器在翻译过程中执行哪些计算在某种程度上是实现质量问题。
\n在我发现的所有三种情况中,翻译时评估的触发器都是基于使用调用结果的目标的要求constexpr。从不考虑函数的参数是否constexpr是文字(尽管这是有效评估的先决条件)。
因此,为了深入了解这一点,constexpr翻译过程中的评估似乎是由以下因素触发的:
我希望这对我以外的人有帮助。感谢所有做出贡献的人。
\n| 归档时间: |
|
| 查看次数: |
676 次 |
| 最近记录: |