Почему не оператор [] из 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
с помощью время выполнения.