/ / activer l'opérateur de conversion à l'aide de SFINAE - c ++, modèles, sfinae, typetraits, enable-if

Activer l'opérateur de conversion à l'aide de SFINAE - c ++, modèles, sfinae, typetraits, enable-if

J'essaye de surcharger operator T() utiliser SFINAE pour renvoyer une copie lorsque T est un type fondamental et une référence const lorsque T est une classe.

Lorsque vous utilisez un double dans mon exemple ci-dessous, je ne peux pas "obtenir la 2ème surcharge (avec std::is_class) à supprimer.

Autrement dit, l'erreur que je reçois est:

error: no type named ‘type’ in ‘struct std::enable_if<false, const double&>’
operator typename std::enable_if< std::is_class<T>::value, const T&>::type () const
^

Qu'est-ce que je fais mal?

#include <iostream>
#include <type_traits>

template<typename T>
struct Foo
{
operator typename std::enable_if<!std::is_class<T>::value, T >::type () const
{
return _val;
}

operator typename std::enable_if< std::is_class<T>::value, const T&>::type () const
{
return _val;
}

T _val;
};

int main()
{
Foo<double> f1;
f1._val = 0.3;

double d = f1;
std::cout << d << std::endl;
return 0;
}

Réponses:

9 pour la réponse № 1

T est déjà connu au moment où votre élèveles fonctions sont instanciées, donc aucune substitution ne se produit, et au lieu de SFINAE, vous obtenez une erreur matérielle. La solution de contournement la plus simple consiste à introduire un paramètre de modèle factice pour ces surcharges d'opérateur et à le définir par défaut sur T de sorte que la déduction de type peut toujours se produire.

template<typename U = T>
operator typename std::enable_if<!std::is_class<U>::value, U >::type () const
{
return _val;
}

template<typename U = T>
operator typename std::enable_if< std::is_class<U>::value, const U&>::type () const
{
return _val;
}

Démo en direct


3 pour la réponse № 2

Tout en ne résolvant pas le problème de savoir pourquoi l'opérateur incorrect n'a pas été rejeté, pour résoudre le problème particulier à résoudre, c'est-à-dire pour retourner par const ref pour les types de classe ou par valeur pour les autres, une solution peut être trouvée en utilisant std::conditional.

template< bool B, class T, class F >
struct conditional;

Fournit le type membre typedef, qui est défini comme T si B est vrai à compiler le temps, ou comme F si B est faux.

Exemple de travail:

#include <iostream>
#include <type_traits>

template<typename T>
struct Foo
{
operator typename std::conditional<
std::is_class<T>::value, const T&, T>::type () const
{
return _val;
}

T _val;
};

int main()
{
Foo<double> f1;
f1._val = 0.3;

double d = f1;
std::cout << d << std::endl;
return 0;
}

-2 pour la réponse № 3

Vous devez lire la définition de std :: enable_if

modèle <bool B, classe T = void> struct enable_if;

"Si B est vrai, std :: enable_if a un type de typedef de membre public, égal à T; sinon, il n'y a pas de typedef de membre."