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
What Is the Most Efficient Thread-Safe C++ Logger
Set Breakpoint in C or C++ Code Programmatically for Gdb on Linux
Why Use #Define Instead of a Variable
Why Does My Cout Output Not Appear Immediately
Why How to Define Structures and Classes Within a Function in C++
Finding Memory Leaks in a C++ Application with Visual Studio
Classification of Detectors, Extractors and Matchers
#Define Sqr(X) X*X. Unexpected Answer
How to Use Other C++ Compilers with Cuda on Windows
How and When to Align to Cache Line Size
What Is the Purpose of Std::Make_Pair VS the Constructor of Std::Pair
Outputting More Things Than a Polymorphic Text Archive
Initializing a Vector of Vectors Having a Fixed Size with Boost Assign