可以在编译时使用`constexpr std :: initializer_list`但不使用ODR吗?

Kyl*_*and 1 c++ one-definition-rule constexpr c++11

在下面的独立程序中,我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;
}
Run Code Online (Sandbox Code Playgroud)

然而,即使有-O3,既clang++3.7(从源代码编译之前的3.7版本)和g++5.1给出一个类似的错误; clangread 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而没有迭代它的任何东西,事实上这个begin()方法确实标记constexpr为C++ 14.那么有什么东西可以用一个constexpr std::initializer_list不需要ODR定义的东西来实现吗?

注意:我正在编译-std=c++14两个编译器,但我意识到它们可能不完全符合 - 即使我使用的版本是相当新的.我有兴趣知道更多最新版本是否允许上述代码.

编辑:与ChrisBeck讨论后改变了我的例子和我的分析; 请参阅他的回答下的讨论,以及编辑此问题的历史记录.

编辑2:根据TC的建议,我constexprfor循环中移除,离开for (auto i : Foo::MyNumbers).这导致undefined reference to 'Foo::MyNumbers'与GCC和Clang 的链接错误.

Chr*_*eck 6

ODR不依赖于优化选项.ODR是标准的一部分.

该标准未参考优化选项.相反,不同的编译器应该按照他们认为合适的方式构成不同的优化方案,并且具有很大的余地.ODR应该确保符合规范的代码将链接到所有符合要求的编译器.(谢谢C++标准委员会!)

所以,请不要忘记循环展开以及链接时的含义.对于ODR而言,唯一重要的是是否使用了ODR.

我无法想到在编译时可以有效完成的任何事情......除了循环展开和初始化对象

由于C++ 14 std::initializer_list是文字类型.因此,您可以在编译时计算中轻松使用它.std::initializer_list在某些代码库中,使用a初始化具有constexpr构造函数的对象非常常见.