Функция-член constexpr с элементом данных std :: vector в C ++ - PullRequest
23 голосов
/ 26 апреля 2019

Я пытаюсь реализовать в классе C ++ функцию-член constexpr, которая возвращает параметр шаблона.Код должен быть совместим с c ++ 11.Однако я сталкиваюсь с проблемами компиляции, когда шаблонный класс также содержит контейнеры STL в качестве элементов данных, таких как std :: vector (которые не затрагиваются функцией-членом constexpr).

Минимальный пример дает следующий код:


#include <vector>
#include <iostream>
#include <array>


template<size_t n>
struct A 
{

  constexpr size_t dimensions() const
  {
    return n;
  }
private:
  std::vector<double> a;
};


int main(int argc,char ** argv)
{
  auto a=A<3>();
  std::array<double,a.dimensions()> arr;

}

Код правильно компилируется с помощью команд

g ++ -std = c ++ 14 -O3 quickTest.cpp -o test -Wall

clang ++ -std = c ++ 11 -O3 quickTest.cpp -o test -Wall

, но не удается при использовании

g ++ -std = c ++ 11 -O3 quickTest.cpp -o test -Wall

с ошибкой

quickTest.cpp:22:33: error: call to non-‘constexpr’ function ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’
   std::array<double,a.dimensions()> arr;
                     ~~~~~~~~~~~~^~
quickTest.cpp:10:20: note: ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’ is not usable as a ‘constexpr’ function because:
   constexpr size_t dimensions() const
                    ^~~~~~~~~~
quickTest.cpp:22:33: error: call to non-‘constexpr’ function ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’
   std::array<double,a.dimensions()> arr;
                     ~~~~~~~~~~~~^~
quickTest.cpp:22:33: note: in template argument for type ‘long unsigned int’

Почему код не компилируется с gcc -std=c++11, но компилируется с clang++ -std=c++11?Как можно заставить этот фрагмент кода работать со старыми версиями gcc, которые многие не поддерживают c ++ 14/17, но только c ++ 11?

Я использую gcc 8.1.1 и clang 6.0.1

1 Ответ

20 голосов
/ 26 апреля 2019

C ++ 11 имеет правило [dcl.constexpr] / 8 :

... Класс, членом которого является эта функция, должен быть литеральным типом ( [basic.types] ).

struct A не является литеральным типом из-за vector, поэтому его нестатические функции-члены не могут быть constexpr.

Таким образом, GCC вправе отклонить код в режиме C ++ 11.

C ++ 14 снято это ограничение.

Решением для C ++ 11 является объявление dimensions() static:

  static constexpr size_t dimensions()
  {
    return n;
  }

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

...