【发布时间】:2016-08-10 18:28:36
【问题描述】:
在以下独立程序中,我预计 for 循环会在编译时展开,甚至完全计算,从而使 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 而不迭代它,实际上是the begin() method is indeed marked constexpr as of C++14 来有用地完成的事情。那么有什么可以通过constexpr std::initializer_list 有效地完成而不需要定义 ODR 的吗?
注意:我在两个编译器上都使用-std=c++14 进行编译,但我意识到它们可能并不完全一致——即使我使用的版本是相当 最近。我很想知道是否有更多最新版本允许上面的代码。
编辑:在与 ChrisBeck 讨论后更改了我的示例和分析;请参阅他的回答下的讨论,以及此问题的编辑历史记录。
编辑 2: 在 T.C. 的建议下,我从 for 循环中删除了 constexpr,留下了 for (auto i : Foo::MyNumbers)。这会导致 GCC 和 Clang 出现 undefined reference to 'Foo::MyNumbers' 链接错误。
【问题讨论】:
-
您的新示例与 odr-use 无关,与基于范围的
for规范有关。 -
@T.C.哎呀。如果您指的是我在
constexpr函数中使用std::cout,那是草率编辑的产物。我已经纠正了。据我所知,从 C++14 开始,getSum中的所有内容都应该在constexpr函数中是允许的。 -
不。你正在做相当于
auto __begin = Foo::MyNumbers.begin(); constexpr auto i = *__begin;。 -
@T.C. ....或者您是说在
constexpr上下文中从不允许基于范围的for? -
IIRC,如果不使用 ODR,您将无法访问数组的元素,
initializer_list基于数组。但是,您可以对这些地址进行指针运算,例如Foo::MyNumbers.end() - Foo::MyNumbers.begin()。 clang++ 拒绝在编译时读取initializer_list的元素,请参阅melpon.org/wandbox/permlink/InGwn1kW94rcuXh0 -- gcc 可以这样做。
标签: c++ c++11 constexpr one-definition-rule