为什么 std::array 临时 constexpr 的 operator[] 不是?

Why isn't the operator[] of a std::array temporary constexpr?

我正在将一些值填充到 constexpr std::array 中,然后在我发现不能将元素用作 [=15] 时继续将编译时静态优点放入更多 constexpr 值中=] C++11 中的初始值设定项。

这是因为std::array::operator[]实际上直到C++14才被标记为constexpr

编译器标志升级后,我现在可以使用 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

我相信你不能使用第二个 arrayoperator [],因为与第一个 array 不同,第二个本身不是 constexpr所以你试图用运行时值初始化 b

第二个示例中的临时 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

替代@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[] 更 "agressive"。

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

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