[英]Can a `constexpr std::initializer_list` be used at compile time but not ODR-used?
在下面的独立程序中,我希望在编译时将for
循环展开,甚至完全计算出来,从而使Foo::MyNumbers
在链接时Foo::MyNumbers
需要:
struct Foo
{
constexpr static auto MyNumbers =
{
3,
28,
200,
};
};
constexpr int getSum(void)
{
auto sum = 0;
for (constexpr auto i : Foo::MyNumbers)
{
sum += i;
}
return sum;
}
但是,即使使用-O3
, clang++
3.7(从3.7发行版之前的源代码构建)和g++
5.1都给出了类似的错误。 clang
说read of non-constexpr variable '__begin' is not allowed in a constant expression
,而g++
说the value of '__for_begin' is not usable in a constant expression
。
我真的想不出任何可以在编译时使用std::initizlizer_list
进行迭代std::initizlizer_list
无需std::initizlizer_list
进行迭代的事情,并且begin()
方法确实在C ++ 14中被标记为constexpr
。 那么,有什么可以用不需要ODR定义的constexpr std::initializer_list
有用地完成的呢?
注:我与编译-std=c++14
的两种编译器,但我知道这可能是他们并不完全符合-尽管我使用的版本是相当最近。 我想知道是否有更多最新版本允许上述代码。
编辑:在与ChrisBeck讨论后更改了我的示例和分析; 查看他的回答下的讨论,以及该问题的编辑历史记录。
编辑2:在TC的建议下,我从for
循环中删除了constexpr
,而保留for (auto i : Foo::MyNumbers)
。 这将导致对GCC和Clang的undefined reference to 'Foo::MyNumbers'
链接错误的undefined reference to 'Foo::MyNumbers'
。
ODR不依赖于优化选项。 ODR是标准的一部分。
该标准未引用优化选项。 取而代之的是,不同的编译器应该根据自己的需要组成不同的优化方案,并且还有很多余地。 ODR应该确保一致的代码将在所有一致的编译器上链接。 (感谢C ++标准委员会!)
因此,您无需考虑循环展开以及在链接时意味着什么。 对于ODR唯一重要的是是否使用了ODR。
我真的想不出在编译时可以有用地完成的任何事情……除了循环展开和初始化对象外
由于C ++ 14 std::initializer_list
是文字类型。 因此,您可以轻松地在编译时计算中使用它。 在某些代码库中,使用std::initializer_list
具有constexpr构造函数的对象非常普遍。
for (constexpr auto i : Foo::MyNumbers)
{
sum += i;
}
无论包含它的函数是否为constexpr
,这都是无效的,因为它将扩展为
{
auto&& __range = Foo::MyNumbers;
for(auto __begin = __range.begin(), __end = __range.end();
__begin != __end;
++__begin) {
constexpr auto i = *__begin;
sum += i;
}
}
*__begin
显然不是一个常数表达式(它需要在非constexpr
变量__begin
值到右值的转换),因此不能用于初始化constexpr
变量i
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.