Nadrzędny Typ powrotu w specjalizacji szablonu funkcji

Chciałbym wyspecjalizować szablon funkcji w taki sposób, że typ zwracania zmienia się w zależności od typu argumentu szablonu.

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() { ... }
Czy to możliwe? Nie mogę używać C++11.
Author: M. Dudley, 2013-04-10

4 answers

Ponieważ specjalizacja musi zgadzać się z szablonem bazowym na typie powrotu, możesz to zrobić, dodając "cechę typu powrotu", strukturę, którą możesz specjalizować i narysować prawdziwy typ powrotu z:

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

Przykład na żywo.

Zauważ, że możesz chcieć trzymać się poniższych wskazówek, więc musisz tylko zaktualizować Typ powrotu w specjalizacji item_return.

template<>
item_return<float>::type foo<float>(){ ... }
// note: No `typename` needed, because `float` is not a dependent type
 44
Author: Xeo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-09 20:49:39

Być może przydałby się następujący hack. Biorąc pod uwagę te proste cechy typu:

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

Możesz napisać swoją klasę i funkcję członka specjalisty w następujący sposób:

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

Prosty program testowy (używa C++11 Tylko do weryfikacji):

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, "!");
}

Oto przykład na żywo.

 5
Author: Andy Prowl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-09 20:59:28

Możesz zrobić specjalizacje szablonów tak:

template<typename T>
T item() {
    return T();
}

template<>
float item<float>() {
    return 1.0f;
}
 4
Author: Rapptz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-09 20:33:07

Wykonaj całą specjalizację w klasie worker i użyj prostej funkcji jako owijki, która będzie wyspecjalizowana w sposób niejawny.

#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";
   }

W tym przykładzie, specjalizacja unsigned char powoduje, że zostanie ona przekonwertowana na int tak, że cout wyświetli ją jako liczbę zamiast jako znak, generując następujące wyjście...

a=A, b=66
 4
Author: nobar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-23 05:22:45