为什么 std::array 的运算符 [] 不是临时的 constexpr?

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

本文关键字:constexpr std array 运算符 为什么      更新时间:2023-10-16

当我发现不能在c++ 11中使用元素作为constexpr初始化器时,我正在将一些值填充到constexpr std::array中,然后继续将编译时的静态优点填充到更多的constexpr值中。

这是因为std::array::operator[]实际上直到c++ 14才被标记为constexpr: https://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!

我从clang++ 3.6中得到-std=c++14:

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 ?

第二个示例中的临时array本身不是const,因此最终调用非constoperator[]过载,而不是constexpr。如果您先将array转换为const,则可以使代码正常工作。

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

现场演示

对于@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<0>(std::array<int, 1>{{3}}) .

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