【问题标题】:Why isn't the operator[] of a std::array temporary constexpr?为什么 std::array 临时 constexpr 的 operator[] 不是?
【发布时间】:2015-10-19 19:34:25
【问题描述】:

当我发现在 C++11 中不能将元素用作 constexpr 初始值设定项时,我正在将一些值填充到 constexpr std::array 中,然后将编译时静态特性继续添加到更多 constexpr 值中.

这是因为 std::array::operator[] 实际上直到 C++14 才标记为 constexprhttps://stackoverflow.com/a/26741152/688724

编译器标志升级后,我现在可以使用 constexpr std::array 的元素作为 constexpr 值:

#include <array>

constexpr std::array<int, 1> array{{3}};
// Initialize a constexpr from an array member through its const operator[]
// that (maybe?) returns a const int & and is constexpr
constexpr int a = array[0];  // Works in >=C++14 but not in C++11

但有时我想在 constexpr 计算中使用临时数组,但那不起作用。

// Initialize a constexpr from a temporary
constexpr int b = std::array<int, 1>{{3}}[0];  // Doesn't work!

我从带有 -std=c++14 的 clang++ 3.6 得到这个:

prog.cc:9:15: error: constexpr variable 'b' must be initialized by a constant expression
constexpr int b = std::array<int, 1>{{3}}[0];  // Doesn't work!
              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:9:19: note: non-constexpr function 'operator[]' cannot be used in a constant expression
constexpr int b = std::array<int, 1>{{3}}[0];  // Doesn't work!
                  ^
/usr/local/libcxx-3.5/include/c++/v1/array:183:41: note: declared here
    _LIBCPP_INLINE_VISIBILITY reference operator[](size_type __n)             {return __elems_[__n];}
                                        ^
1 error generated.

我要索引的两个变量有什么区别?为什么我不能将直接初始化的临时std::arrayoperator[] 用作constexpr

【问题讨论】:

    标签: c++ c++11 c++14 constexpr stdarray


    【解决方案1】:

    第二个示例中的临时array 本身不是const,因此您最终调用了非const operator[] 重载,而不是constexpr。如果您首先将array 转换为const,您可以让您的代码工作。

    constexpr int b = static_cast<std::array<int, 1> const&>(std::array<int, 1>{{3}})[0];
    

    Live demo

    【讨论】:

    • 哦,当然!我需要再玩一些,但你有什么理由不应该将非常量operator[] 也标记为constexpr?是的,它返回一个非const 引用,但据我所知,C++14 rule relaxation 将编译时计算与 cv 限定分开。那么这样做会有什么副作用吗? constexpr reference operator[](size_type n); constexpr const_reference operator[](size_type n) const;
    • 似乎工作正常:Live demo
    • @XoWang 我不确定这样做会产生什么后果。看起来标准库中对成员函数的所有 C++14 constexpr 添加仅适用于 const 重载,因此意图似乎是这些函数不应该改变数据成员,但同样,我不知道是什么原因。
    • coliru.stacked-crooked.com/a/8f8088ae04a41f3e 是一种更漂亮的方式——只需将array 直接创建为const array 而不是强制转换。
    • 现在委员会中有一个 paper(PDF),它允许 std::array 在 constexpr 上下文中产生副作用,包括 reference operator[] (index_type)
    【解决方案2】:

    除了@Praetorian 的解决方法,您可以使用std::get(std::array)

    #include<array>
    int main(){
        constexpr int b = 
        //  std::array<int, 1>{{3}}[0]; // Doesn't work!
        //  static_cast<std::array<int, 1> const&>(std::array<int, 1>{{3}})[0]; // long but Works!
            std::get<0>(std::array<int, 1>{{3}});// Works!
    }
    

    我认为std::get 在生成constexpr 时比operator[] 更“激进”。

    (使用clang 3.5gcc 5.0 C++14 测试,应该适用于C++11)

    另外,由于某种原因(与模板参数有关),ADL在这里不起作用,所以不能只写get&lt;0&gt;(std::array&lt;int, 1&gt;{{3}})

    【讨论】:

      【解决方案3】:

      我相信您不能使用第二个arrayoperator [],因为与第一个array 不同,第二个本身不是constexpr,因此您正在尝试初始化b具有运行时值。

      【讨论】:

        猜你喜欢
        • 2016-03-15
        • 1970-01-01
        • 2020-10-30
        • 1970-01-01
        • 2015-12-14
        • 1970-01-01
        • 2021-05-07
        • 2016-08-06
        相关资源
        最近更新 更多