繁体   English   中英

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

[英]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;
}

但是,即使使用-O3clang++ 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进行迭代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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM