Je voudrais spécialiser un modèle de fonction de telle sorte que le type de retour change en fonction du type de l'argument du modèle.
class ReturnTypeSpecialization
{
public:
template<typename T>
T Item();
};
// Normally just return the template type
template<typename T>
T ReturnTypeSpecialization::Item() { ... }
// When a float is specified, return an int
// This doesn't work:
template<float>
int ReturnTypeSpecialization::Item() { ... }
Est-ce possible? Je ne peux pas utiliser C++ 11.
Puisque la spécialisation doit être d'accord avec le modèle de base sur le type de retour, vous pouvez le faire en ajoutant un "trait de type de retour", une structure à partir de laquelle vous pouvez spécialiser et dessiner le vrai type de retour:
// in the normal case, just the identity
template<class T>
struct item_return{ typedef T type; };
template<class T>
typename item_return<T>::type item();
template<>
struct item_return<float>{ typedef int type; };
template<>
int item<float>();
Notez que vous souhaiterez peut-être vous en tenir à ce qui suit, il vous suffit donc de mettre à jour le type de retour dans le item_return
spécialisation.
template<>
item_return<float>::type foo<float>(){ ... }
// note: No `typename` needed, because `float` is not a dependent type
Faites toute la spécialisation dans une classe de travail et utilisez une fonction simple comme wrapper qui sera spécialisée implicitement.
#include <iostream>
using std::cout;
// worker class -- return a reference to the given value
template< typename V > struct worker
{
typedef V const & type;
static type get( V const & v ) { return v; }
};
// worker class specialization -- convert 'unsigned char' to 'int'
template<> struct worker<unsigned char>
{
typedef int type;
static type get( unsigned char const & v ) { return v; }
};
// mapper function
template< typename V > typename worker<V>::type mapper( V const & v )
{
return worker<V>::get(v);
}
int main()
{
char a='A';
unsigned char b='B';
cout << "a=" << mapper(a) << ", b=" << mapper(b) << "\n";
}
Dans cet exemple, la spécialisation de unsigned char
le convertit en int
afin que cout
l'affiche sous forme de nombre plutôt que de caractère, générant la sortie suivante ...
a=A, b=66
Vous pourriez peut-être utiliser le hack suivant. Compte tenu de ces traits de caractère simples:
template<bool b, typename T, typename U>
struct conditional { typedef T type; };
template<typename T, typename U>
struct conditional<false, T, U> { typedef U type; };
template<typename T, typename U>
struct is_same { static const bool value = false; };
template<typename T>
struct is_same<T, T> { static const bool value = true; };
Vous pouvez écrire votre classe et votre fonction membre spécialisée comme suit:
class ReturnTypeSpecialization
{
public:
template<typename T>
typename conditional<is_same<T, float>::value, int, T>::type
Item();
};
// Normally just return the template type
template<typename T>
typename conditional<is_same<T, float>::value, int, T>::type
ReturnTypeSpecialization::Item() { return T(); }
// When a float is specified, return an int
template<>
int ReturnTypeSpecialization::Item<float>() { return 1.0f; }
Programme de test simple (utilise C++ 11 uniquement pour la vérification):
int main()
{
ReturnTypeSpecialization obj;
static_assert(std::is_same<decltype(obj.Item<bool>()), bool>::value, "!");
static_assert(std::is_same<decltype(obj.Item<float>()), int>::value, "!");
}
Voici un exemple en direct .
Vous pouvez faire des spécialisations de modèle comme ceci:
template<typename T>
T item() {
return T();
}
template<>
float item<float>() {
return 1.0f;
}