4 votes

Spécialisation des modèles C++ pour les variables constantes

J'essaie actuellement d'avoir une variable constante à la compilation qui est spécialisée pour plusieurs types. Actuellement, j'utilise des expressions constantes telles que l'exemple généralisé suivant :

template<typename T>
constexpr T GENERAL_CONSTANT = T(0.01);

template<> constexpr float GENERAL_CONSTANT<float> = float(0.02);

template<> constexpr double GENERAL_CONSTANT<double> = double(0.03);

Ce code ne semble toutefois fonctionner qu'avec certains compilateurs/liens. Il compile et fonctionne correctement avec Clang 9.0.0 pour Windows 10, Clang 6.0.0 pour Windows 10, Clang 6.0.0 pour Ubuntu 18.04, et GCC pour Ubuntu 18.04. Mais il a donné des erreurs similaires de redéfinition multiple dans plusieurs autres configurations telles que Clang 10.0.0 sur Windows 10 ou Clang 10.0.0 sur Unix, ainsi que quelques autres. Les erreurs ressemblent souvent à ceci :

/usr/bin/ld: <some path to a.cpp> multiple definition of `GENERAL_CONSTANT<double>'; <some path to a.cpp>: first defined here
/usr/bin/ld: <some path to a.cpp> multiple definition of `GENERAL_CONSTANT<float>'; <some path to a.cpp>: first defined here

Où 'a.cpp' est le fichier qui utilise les constantes, mais ne les définit pas. Etant donné que cette erreur se produit de manière incohérente en fonction du compilateur et de la machine, j'étais curieux de savoir s'il s'agissait d'une approche non standard de ce problème, et si c'est le cas, quelle approche devrais-je adopter à la place ?

4voto

Piotr S. Points 9759

const qualification d'un modèle de variable (et constexpr fait d'un objet const ) n'implique pas lien interne , [basic.link]/p3 :

Un nom ayant la portée d'un espace de noms a un lien interne s'il est le nom de

  • une variable, modèle de variable , une fonction ou un modèle de fonction qui est déclaré explicitement statique ; ou

  • a variable non-modèle de l'information non volatile type qualifié de const , sauf [...]

Il semble qu'il s'agisse d'un changement récent ( CWG 2387 ) :

Notes de la téléconférence de décembre 2018 :

Le CWG a estimé qu'un const ne doit pas affecter la liaison d'un modèle de variable ou de ses instances.

et cela explique la différence que vous avez observée dans Clang-10.

Une solution consiste à marquer le modèle de variable et ses spécialisations comme suit static o inline . La première impose un lien interne, tandis que la seconde exclut les instances de modèles variables de la règle de la définition unique, ce qui permet des définitions multiples à condition qu'elles se trouvent dans des unités de traduction distinctes.

3voto

Jan Schultke Points 151

Ce code se compile tel quel. Voir Cette démo . Les variables de modèle spécialisées seront toujours compilées dans le binaire, même si elles sont marquées constexpr . Comme vous utilisez l'en-tête et donc ces variables dans plusieurs unités de traduction, vous obtenez une erreur de l'éditeur de liens. Vous pouvez le constater par le fait que ld est à l'origine de l'erreur.

Marquer les spécialisations inline empêchera cette situation de se produire et résoudra le problème :

template<typename T>
constexpr T GENERAL_CONSTANT = T(0.01);

template<> inline constexpr float GENERAL_CONSTANT<float> = float(0.02);

template<> inline constexpr double GENERAL_CONSTANT<double> = double(0.03);

Il s'agit d'un bogue du compilateur, car constexpr implique inline pour les variables et les fonctions, mais apparemment, certaines versions du compilateur ne respectent pas cette règle pour les spécialisations des modèles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X