Overriding Return Type in Function Template Specialization

Overriding return type in function template specialization

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

function template specialization with return type argument

Specializing a return type isn't really different than any other specialization. The problem isn't with how this works, but how it is called.

template<class T1,class T2>
inline T1 func(const T2& a)
{
return T1(3.5);
}

func(2); //with T2 = int, what is T1?

The compiler has no way to know what the return type should be. A specialization is specific instructions on what to do if the template parameters match, so it still needs both template parameters first. If you specify the first template parameter, it will work.

func<float>(2); //returns 1.0

As noted in the comments, though, overloading is preferable to specialization.

float func(const int&);
double func(const float&);

This way, it doesn't get stuck on guessing a return type.

method template specialization by return type

You cannot specialize inside a class scope. According to the C++ standard,

14.7.3/2 An explicit specialization shall be declared in a namespace enclosing the specialized template.

Therefore you should specialize the template member function at namespace scope,

template<> // this should be outside the primary template class definition
bool Foo::method() {
return true;
}

Is it possible to change return type of a specialized template function?

An easy way to specialize the return type is the use of std::conditional:

// First approach: conditional
template<int I> struct banana {
float number;
banana(float n) {
number = n;
}

// C++14 std::conditional_t<I == 0, float, int>
typename std::conditional<I == 0, float, int>::type
getNumber() {
return number;
}
};

Or as you suggested you could use template specialization:

template<int /*I*/>
struct banana_return_type
{
using type = int;
};

template<>
struct banana_return_type<0>
{
using type = float;
};

template<int I> struct bananaSecond {
float number;
bananaSecond(float n) {
number = n;
}

typename banana_return_type<I>::type
getNumber() {
return number;
}
};

Demo

How to use derived type in specialisation of return-type function template? (couldn't infer template argument)

The compiler already told you what the problem is:

note: candidate template ignored: couldn't infer template argument 'T'

You need to specify the template parameter explicitly.

template <>
typename ReturnType<Foo>::type build_wrapped<Foo>()
{ // ^~~~~
Foo t{};
return typename ReturnType<Foo>::type(t);
}

Function template overloading (different return value type)

Consider a class template partial specialization:

template<class U, class V> class T { };

template<class V> class T<void, V> { };

When you write T<void, int>, the partial specialization will be used.

Now consider a function template:

template <typename R, typename T>
R convert(T const&) { return /* something */; }

Note that the order of R and T are swapped in the template parameter list above. This is probably how such a template would be written - you write convert<R>(something), explicitly specifying the destination type while letting the source type be deduced by the compiler.

Now suppose you want convert<void>(something) to do something different. You can't do it with an overload:

template <typename T>
void convert(T const&) { }

If you write convert(something) - which would previously be ill-formed, it will go to your new overload, because the compiler can't deduce R for the first template. But if you write convert<void>(something) or even convert<void, T>(something), it would still go to the original template. To make it worse, something like convert<int>(1) is now ill-formed because it's ambiguous.

In other words, you can't make convert<void, T>(something) use a different implementation than convert<int, T>(something), whereas you can do this with class template partial specializations.

Use return type and parameter type of function as template types

Yessir.

template <class Function>
struct BarFor_;

template <class Ret, class In>
struct BarFor_<Ret(*)(In)> {
using type = Bar<Ret, In>;
};

template <auto function>
using BarFor = typename BarFor_<decltype(function)>::type;

Now you can get your type via:

 BarFor<foo> b;

See it live on Coliru



Related Topics



Leave a reply



Submit