web-dev-qa-db-fra.com

Remplacement du type de retour dans la spécialisation de modèle de fonction

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.

46
M. Dudley

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>();

exemple en direct.

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
48
Xeo

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
5
nobar

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 .

5
Andy Prowl

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;
}
4
Rapptz