Avertissement de clavier concernant le constexpr statique basé sur un modèle (la fonction inline n’est pas définie)

J’ai le code c ++ suivant:

#include  #include  typedef unsigned char uchar; class A { public: template  static inline constexpr std::array filledArray() { std::array ret{}; ret.fill(value); return ret; } std::array upper = A::filledArray(); }; int main() { A blah; for (int i = 0; i < 5; ++i) std::cout << blah.upper[i] << std::endl; return 0; } 

g ++ le comstack sans avertissements et le résultat est As, comme prévu. mais clang ++ – 4.0 produit:

 clang++-4.0 -std=c++14 main.cpp -o clangOut main.cpp:9:47: warning: inline function 'A::filledArray' is not defined [-Wundefined-inline] static inline constexpr std::array filledArray() { ^ main.cpp:15:34: note: used here std::array upper = A::filledArray(); ^ 1 warning generated. /tmp/main-b6fac8.o: In function `A::A()': main.cpp:(.text._ZN1AC2Ev[_ZN1AC2Ev]+0x15): undefined reference to `std::array A::filledArray()' clang: error: linker command failed with exit code 1 (use -v to see invocation) 

semble que clang is ne voit pas, que j’instancie la fonction filledArray. si j’appelle filledArray avec les arguments de modèle appropriés dans la fonction principale ou toute autre fonction, l’avertissement disparaît et clangOut s’imprime également comme prévu.

  1. Est-ce que je fais quelque chose de stupide ici?
  2. la version de gcc fait-elle ce que je pense (initialise le haut avec As au moment de la compilation)?
  3. est-ce un bug dans Clang?

  1. Est-ce que je fais quelque chose de stupide ici?

Oui, la fonction filledArray() appelle toujours un std::array:fill non-constexpr, donc le déclarer constexpr est à proprement parler une erreur (selon [dcl.constexpr] / 5 “le programme est mal formé, aucun diagnostic requirejs “).

  1. la version de gcc fait-elle ce que je pense (initialise le haut avec As au moment de la compilation)?

De nombreux compilateurs assouplissent l’ exigence [dcl.constexpr] / 5 et ignorent silencieusement constexpr lorsqu’il est utilisé dans un contexte non-constexpr. Mais avec l’optimisation, ils peuvent aussi facilement voir à travers des appels en ligne tels que la construction de std::array et std::array::fill() et évalueront probablement votre fonction à la compilation, même si elle n’a pas été déclarée constexpr ( démo ).

  1. est-ce un bug dans Clang?

Oui, c’est un bug grave ( # 18781 ).

Clang ne peut pas comstackr static constexpr membres static constexpr classe static constexpr . Il ne peut pas “voir” correctement lorsque de tels éléments sont utilisés par ODR. Pour vérifier, vous pouvez simplement placer A::filledArray<5, 'A'>(); par lui-même quelque part dans main() , cela “corrigera” la compilation (mais pas le mauvais format).

Un autre exemple:

 #include  struct foo { constexpr static const char* me = "foo"; }; int main () { foo f; std::cout << f.me << std::endl; } 

Changer de f.me en foo::me "corrige" aussi.

Pour contourner le constexpr vous pouvez remplacer constexpr par const .

  1. Est-ce que je fais ce que je pense? -> non (testé en fixant un point d’arrêt)

ce qui suit (inspiré de la réponse à Array Initialization Comstack Time – Constexpr Sequence )

 #include  #include  #include  template  constexpr T generate_ith_number(const std::size_t) { static_assert(std::is_integral::value, "T must to be an integral type"); return value; } template  constexpr auto make_sequence_impl(std::integer_sequence) { return std::integer_sequence(Is)...>{}; } template  constexpr auto make_sequence() { return make_sequence_impl(std::make_integer_sequence{}); } template  constexpr auto make_array_from_sequence_impl(std::integer_sequence) { return std::array{Is...}; } template  constexpr auto make_array_from_sequence(Seq) { return make_array_from_sequence_impl(Seq{}); } typedef unsigned char uchar; class A { public: template  static inline constexpr std::array filledArray() { return make_array_from_sequence(make_sequence()); } // long route std::array upper = A::filledArray<5, 'A'>(); // taking a short cut std::array blah = make_array_from_sequence_impl(make_sequence()); void dummy() {A::filledArray<5, 'A'>();} // make clang happy }; int main() { A blah; for (int i = 0; i < 5; ++i) std::cout << blah.upper[i] << std::endl; for (int i = 0; i < 45; ++i) std::cout << blah.blah[i] << std::endl; return 0; } 

qui effectivement répond également # 1. oui, c’est stupide d’essayer d’optimiser un code qui ne sera jamais critique en termes de performances, échouer, heurter des bogues du compilateur et perdre de nombreuses heures à chercher une solution trop prolixe et trop difficile à lire pour la production. :RÉ