web-dev-qa-db-fra.com

fonction membre constexpr avec membre de données std :: vector en C ++

J'essaie d'implémenter dans une classe C++ une fonction membre constexpr qui retourne un paramètre de modèle. Le code est censé être compatible c ++ 11. Cependant, je rencontre des problèmes de compilation lorsque la classe basée sur des modèles contient également des conteneurs STL en tant que membres de données tels que std :: vector (qui ne sont pas modifiés par la fonction membre constexpr).

Un exemple minimal est donné par le code suivant:


#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;

}

Le code se compile correctement avec les commandes

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

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

mais échoue quand j'utilise

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

avec l'erreur

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’

Pourquoi le code ne compile pas avec gcc -std=c++11 mais compile avec clang++ -std=c++11? Comment pourrait-on faire fonctionner cet extrait de code avec des versions plus anciennes de gcc qui ne prennent pas en charge c ++ 14/17, mais seulement c ++ 11?

J'utilise gcc 8.1.1 et clang 6.0.1

23
Luca Parisi

C++ 11 avait une règle [dcl.constexpr]/8 :

... La classe dont cette fonction est membre doit être un type littéral ( [ basic.types] ).

struct A N'est pas un type littéral à cause de vector, donc ses fonctions membres non statiques ne peuvent pas être constexpr.

GCC a donc raison de rejeter le code en mode C++ 11.

C++ 14 supprimé cette restriction.

La solution pour C++ 11 est de déclarer dimensions()static:

  static constexpr size_t dimensions()
  {
    return n;
  }

Démo en direct

20
rustyx