pourquoi le paramètre de modèle qui est explicitement donné ne peut pas être «déduit»
Venant de cette question: Utilisation des valeurs d'énumération en combinaison avec SFINAE
J'ai essayé de mettre en œuvre:
enum Specifier
{
One,
Two,
Three
};
template <Specifier, typename UNUSED=void>
struct Foo
{
void Bar(){ std::cout << "Bar default" << std::endl;}
};
template <Specifier s , typename std::enable_if<s == Specifier::Two || s == Specifier::One, int>::type>
struct Foo<s>
{
void Bar(){ std::cout << "Bar Two" << std::endl; }
};
int main()
{
Foo< One >().Bar();
Foo< Two >().Bar();
}
Échoue avec:
> main.cpp:130:8: error: template parameters not deducible in partial specialization:
130 | struct Foo<s>
| ^~~~~~
main.cpp:130:8: note: '<anonymous>'
Comment corriger cet exemple super simple? J'aime SFINAE :-)
Réponses
Mettez le enable_if
dans Foo
la liste des arguments de modèle de »:
template <Specifier s>
struct Foo<s, typename std::enable_if<s == Specifier::Two || s == Specifier::One, void>::type>
// same as the default type used before ^^^^
démo .
Comme l'erreur nous l'indique, les arguments de modèle ne sont pas déductibles en spécialisation partielle. Dans votre exemple, vous avez essayé de placer la construction SFINAE dans la liste de paramètres de modèle de la spécialisation, mais vous devez la déplacer vers la liste d' arguments de modèle (de la classe en cours de spécialisation) de la déclaration de spécialisation.
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>>
Appliqué à votre exemple (nettoyé un peu):
#include <iostream>
#include <type_traits>
enum class Specifier {
One,
Two,
Three
};
template <Specifier, typename = void>
struct Foo {
static void bar() { std::cout << "bar default\n"; }
};
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>> {
static void bar() { std::cout << "bar One or Two\n"; }
};
int main() {
Foo<Specifier::One>::bar(); // bar One or Two
Foo<Specifier::Two>::bar(); // bar One or Two
Foo<Specifier::Three>::bar(); // bar default
}
Notez que vous n'avez pas besoin de nommer le paramètre de modèle de type non utilisé dans le modèle principal du modèle de classe Foo
.
C'est un fait simple que les arguments de modèle dans les spécialisations de modèle ne sont pas déductibles.
Non pas que vous en ayez besoin.
Changez simplement la spécialisation du modèle:
template <Specifier s>
struct Foo<s, std::enable_if_t<s == Specifier::Two || s == Specifier::One, int>>
Bien sûr, le résultat d' std::enable_if_t
être ici int
au lieu de le void
rend quelque peu inutile.
De plus, comme d'autres l'ont commenté, utiliser des concepts ou du moins requires
au lieu de l'argument modèle supplémentaire du modèle principal est beaucoup plus pratique.