Overriding return type in function template specialization

C++Templates

C++ Problem Overview


I would like to specialize a function template such that the return type changes depending on the type of the template argument.

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() { ... }

Is this possible? I can't use C++11.

C++ Solutions


Solution 1 - C++

Since the specialization has to agree with the base template on the return type, you can make it so by adding a "return type trait", a struct you can specialize and draw the true return type from:

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

Live example.

Note that you might want to stick to the following, so you only need to update the return-type in the item_return specialization.

template<>
item_return<float>::type foo<float>(){ ... }
// note: No `typename` needed, because `float` is not a dependent type

Solution 2 - C++

Do all of the specialization in a worker class and use a simple function as a wrapper that will be specialized implicitly.

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

In this example, the specialization of unsigned char causes it to be converted to an int so that cout will display it as a number instead of as a character, generating the following output...

a=A, b=66

Solution 3 - C++

Perhaps you could use the following hack. Given these simple type traits:

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

You could write your class and specialized member function as follows:

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

Simple test program (uses C++11 just for verification):

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

Here is a live example.

Solution 4 - C++

You can do template specializations like so:

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

template<>
float item<float>() {
    return 1.0f;
}

Solution 5 - C++

Hi I tried to use the template specialization for returning the parameter value for primitives as well as std::string data, while doing so I was getting lot of unresolved external, redefinition kind of errors. so if any one face something like this, he/she can use something like below when want to return different data types including string, NOTE: both the Template function must be the part of the Header file (*.h)... so we are using template specialization string data type here... inside class as a inline member we have to use template specialize method and in the same file we can define the template as well.

class ConfigFileParser
{
public:
    bool ParseConfigFile(const std::string& file_name);
    template <typename T>
    T GetParameterValue(const std::string key);
    template <>
    std::string GetParameterValue<std::string>(const std::string key)
    {
        std::string param_val = "";
        //do logical operation here... 
        return param_val;
    }
private:
    // private functions...

    // private data...
};

template <typename T>
T ConfigFileParser::GetParameterValue(const std::string key)
{
    T param_val = 0;
    std::stringstream ss;
    std::string val_str;
    // do some operation here...
    ss << val_str.c_str();
    ss >> param_val;

    return param_val;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsourcenouveauView Question on Stackoverflow
Solution 1 - C++XeoView Answer on Stackoverflow
Solution 2 - C++Brent BradburnView Answer on Stackoverflow
Solution 3 - C++Andy ProwlView Answer on Stackoverflow
Solution 4 - C++RapptzView Answer on Stackoverflow
Solution 5 - C++rajendra shindeView Answer on Stackoverflow