Почему не оператор [] из std:: array временный constexpr?

Я набивал некоторые значения в constexpr std::array, а затем продолжал статическую добротность времени компиляции в значениях constexpr, когда обнаружил, что вы не можете использовать элемент как инициализатор constexpr в С++ 11.

Это потому, что std::array::operator[] на самом деле не отмечен constexpr, пока С++ 14: qaru.site/info/195911/...

После обновления флага компилятора я могу теперь использовать элемент 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 = С++ 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::array operator[] как constexpr?

Ответ 1

Временной array в вашем втором примере сам по себе не является const, поэтому вы вызываете перегрузку не const operator[], которая не является constexpr. Вы можете заставить свой код работать, если вы сначала внесете array в const.

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

Живая демонстрация

Ответ 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 более "агрессивен", чем operator[] при создании constexpr.

(Протестировано с помощью clang 3.5 и gcc 5.0 С++ 14, должно работать с С++ 11)

Кроме того, по какой-либо причине (связанной с параметром шаблона) ADL не работает здесь, поэтому невозможно просто написать get<0>(std::array<int, 1>{{3}}).

Ответ 3

Я считаю, что вы не можете использовать второй array operator [], потому что, в отличие от первого array, второй сам не является constexpr, поэтому вы пытаетесь инициализировать b с помощью время выполнения.