Почему std:: array:: size constexpr с простыми типами (int, double,...), но не std::vector (GCC)?

Следующий код:

std::array<int, 4> arr1;
std::array<float, arr1.size()> arr2;

... компилируется как с gcc, так и clang, потому что std::array::size считается constexpr.

Но следующее с помощью gcc (версия 5.3.0 20151204) не компилируется:

std::array<std::vector<int>, 4> arr1;
std::array<std::vector<double>, arr1.size()> arr2;

Для меня нет причин, по которым такой код не должен компилироваться, если первый работает, но поскольку я не нашел много сообщений об этом, я не знаю, является ли это ошибкой gcc или clang расширение?

Ошибка из gcc (что я действительно не понимаю...):

main.cpp: In function 'int main()':
main.cpp:6:46: error: call to non-constexpr function 'constexpr std::array<_Tp, _Nm>::size_type std::array<_Tp, _Nm>::size() const [with _Tp = std::vector<int>; long unsigned int _Nm = 4ul; std::array<_Tp, _Nm>::size_type = long unsigned int]'
     std::array<std::vector<double>, arr1.size()> arr2;
                                              ^
In file included from main.cpp:1:0:
/usr/local/include/c++/5.3.0/array:170:7: note: 'constexpr std::array<_Tp, _Nm>::size_type std::array<_Tp, _Nm>::size() const [with _Tp = std::vector<int>; long unsigned int _Nm = 4ul; std::array<_Tp, _Nm>::size_type = long unsigned int]' is not usable as a constexpr function because:
       size() const noexcept { return _Nm; }
       ^
/usr/local/include/c++/5.3.0/array:170:7: error: enclosing class of constexpr non-static member function 'constexpr std::array<_Tp, _Nm>::size_type std::array<_Tp, _Nm>::size() const [with _Tp = std::vector<int>; long unsigned int _Nm = 4ul; std::array<_Tp, _Nm>::size_type = long unsigned int]' is not a literal type
/usr/local/include/c++/5.3.0/array:89:12: note: 'std::array<std::vector<int>, 4ul>' is not literal because:
     struct array
            ^
/usr/local/include/c++/5.3.0/array:89:12: note:   'std::array<std::vector<int>, 4ul>' has a non-trivial destructor
main.cpp:6:46: error: call to non-constexpr function 'constexpr std::array<_Tp, _Nm>::size_type std::array<_Tp, _Nm>::size() const [with _Tp = std::vector<int>; long unsigned int _Nm = 4ul; std::array<_Tp, _Nm>::size_type = long unsigned int]'
     std::array<std::vector<double>, arr1.size()> arr2;
                                              ^
main.cpp:6:48: note: in template argument for type 'long unsigned int' 
     std::array<std::vector<double>, arr1.size()> arr2;
                                                ^

Ответы

Ответ 1

Я думаю, что это связано с проблемой CWG 1684. Ранее требования constexpr включали:

Класс, членом которого является функция constexpr, является литеральный тип

И std::array<std::vector<int>, 4> не является литеральным типом, и, следовательно, его функция-член size() не будет constexpr. Однако новая формулировка допускает нестатические функции-члены constexpr для нелитеральных типов, предполагая, что эти функции отвечают всем другим требованиям constexpr (что ясно показывает array<T,N>::size()).

В новой редакции это ошибка gcc. Ранее было зарегистрировано как 66297.