Supposons qu'un paramètre de modèle d'entrée T puisse ou non avoir une variable interne bar . J'essaie d'écrire une structure qui renvoie la valeur de bar lorsque nous l'avons, et renvoie une constante lorsque nous ne l'avons pas. Voici ma tentative:
struct A {
static constexpr unsgined int bar = 20;
hasBar = true;
};
struct B {
hasBar = false;
};
template <typename T, typename std::enable_if<T::hasBar, int>::type>
struct getBar {
static constexpr unsigned int bar = T::bar;
};
template <typename T, typename std::enable_if<!T::hasBar, int>::type>
struct getBar {
static constexpr unsigned int bar = 0;
};
int main() {
getBar<A>::bar; // Expect 20
getBar<B>::bar; //Expect 0
}
Je ne peux pas compiler ce code avec C ++ 14. Le compilateur se plaint que: "le paramètre non-type de modèle a un type différent".
Pourquoi avons-nous une telle erreur et comment puis-je y remédier?
3 Réponses :
Les modèles de classes ne peuvent pas être surchargés (comme les modèles de fonctions); Vous pouvez utiliser la spécialisation à la place. par exemple
template <typename T, typename = void>
struct getBar {
static constexpr unsigned int bar = 0;
};
template <typename T>
struct getBar<T, std::enable_if_t<T::hasBar>> {
static constexpr unsigned int bar = T::bar;
};
Vous pouvez détecter si :: bar existe directement sans avoir besoin de hasbar
quelque chose comme ...
#include <type_traits>
#include <iostream>
struct A {
static constexpr unsigned int bar = 20;
};
struct B {
};
template <typename T,typename=void>
struct getBar {
static constexpr unsigned int bar = 0;
};
template <typename T>
struct getBar<T,std::void_t<decltype(T::bar)>> {
static constexpr unsigned int bar = T::bar;
};
int main() {
std::cout << getBar<A>::bar << std::endl; // Expect 20
std::cout << getBar<B>::bar << std::endl; //Expect 0
}
Solution géniale!
Une autre solution qui n'a pas besoin de hasBar mais détecte simplement la présence de bar (et conserve également le type d'origine de bar , si différent de int)
struct A
{ static constexpr unsigned int bar = 20; };
struct B
{ };
template <typename T>
constexpr auto getBarHelper (int) -> decltype( T::bar )
{ return T::bar; }
template <typename T>
constexpr int getBarHelper (long)
{ return 0; }
template <typename T>
struct getBar
{ static constexpr auto bar { getBarHelper<T>(0) }; };
int main()
{
static_assert( 20u == getBar<A>::bar, "!" );
static_assert( 0 == getBar<B>::bar, "!" );
}
Veuillez fournir un exemple reproductible minimal .
Merci @Barry. J'ai modifié le code pour améliorer l'exhaustivité.