web-dev-qa-db-fra.com

Comprendre les variables membres constexpr statiques

J'ai quelques confusions concernant static constexpr variables membres en C++ 11.

Dans first.hpp

template<typename T>
struct cond_I
{ static constexpr T value = 0; }; 


// specialization 
template<typename T>
struct cond_I< std::complex<T> >
{ static constexpr std::complex<T> value = {0,1}; }; 

Dans la fonction main ()

cout << cond_I<double>::value << endl;            // this works fine
cout << cond_I< complex<double> >::value << endl; // linker error

Cependant, si j'ajoute la ligne suivante à first.hpp tout fonctionne bien.

template<typename T1> 
constexpr std::complex<T1> cond_I< std::complex<T1> >::value;

Ce que je comprends (je peux me tromper), c'est que cond_I< std::complex<double> >::value a besoin d'une définition, mais dans le cas précédent, il n'a que la déclaration. Mais qu'en est-il de cond_I<double>::value? Pourquoi ne nécessite-t-il pas de définition?

Encore une fois, dans un autre fichier d'en-tête, second.hpp, J'ai:

Dans second.hpp

// empty struct
template<typename T>
struct eps
{ };


// special cases
template<>
struct eps<double>
{
  static constexpr double value = 1.0e-12;
};

template<>
struct eps<float>
{
  static constexpr float value = 1.0e-6;
};

Dans ce cas, les codes suivants fonctionnent parfaitement sans aucune définition de eps<>::value.

Dans la fonction main ()

cout << eps<double>::value << endl;    //  works fine
cout << eps<float>::value << endl;     //  works fine

Quelqu'un peut-il m'expliquer les différents comportements de static constexpr les variables membres, dans ces scénarios?

Ces comportements sont également les mêmes pour gcc-5.2 et clang-3.6.

19
Titas Chanda

Selon la norme 9.4.2/p3 Membres de données statiques [class.static.data] (Emphasis Mine):

Si un membre de données stat const non volatile est de type intégral ou énumération, sa déclaration dans la définition de classe peut spécifier un initialiseur d'accolade ou égal dans lequel chaque clause d'initialisation qui est une expression d'affectation est une expression constante (5.20 ). n membre de données statiques de type littéral peut être déclaré dans la définition de classe avec le spécificateur constexpr; si tel est le cas, sa déclaration doit spécifier un initialiseur d'accolade ou égal dans lequel chaque clause d'initialisation qui est une affectation-expression est une expression constante. [Remarque: dans ces deux cas, le membre peut apparaître dans des expressions constantes. - end note] Le membre doit toujours être défini dans une étendue d'espace de noms s'il est utilisé par odr (3.2) dans le programme et la définition de la portée de l'espace de noms ne doivent pas contenir d'initialiseur.

Comme M.M l'a expliqué précédemment dans les commentaires, ostream::operator<<(ostream&, const complex<T>&) passe par référence, donc la valeur est considérée comme utilisée par odr dans le programme. Ainsi, comme l'exige le libellé ci-dessus, vous devez fournir une définition.

Maintenant que vous avez déjà découvert que les types fondamentaux sont passés par valeur, c'est pourquoi aucune définition n'est requise.

13
101010