The following code fails to compile because of error: redefinition of ‘template<class Integer, class> void func(Integer)’
#include <iostream>
#include <type_traits>
template<typename Float, typename = typename
std::enable_if<std::is_floating_point<Float>::value>::type>
void func(Float floatVal)
{
std::cerr << "float: " << floatVal << "\n";
}
template<typename Integer, typename = typename
std::enable_if<std::is_integral<Integer>::value>::type>
void func(Integer integer)
{
std::cerr << "integral: " << integer << "\n";
}
int main()
{
func(32.4246);
func(144532);
}
But the two functions will clearly have different signatures on template instantiation. So why is can't this compile?
Please note: I do know how to fix this: just adding another dummy template parameter to one of the functions, e.g. typename=void
, will work, like here
template<typename Integer, typename dummy=void, typename = typename
std::enable_if<std::is_integral<Integer>::value>::type>
void func(Integer integer){}
But the question is why do I have to do this?
N4527 §1.3.19 [defns.signature.templ]
signature
<function template> name, parameter type list (8.3.5), enclosing namespace (if any), return type, and template parameter list
The default template argument is not part of the signature of a function template.
You can change std::enable_if<...>::type
as the return type of the function. As far as I know you cannot pass it to the type of another template parameter.
#include <iostream>
#include <type_traits>
template<typename Float>
typename std::enable_if<std::is_floating_point<Float>::value>::type
func(Float floatVal)
{
std::cerr << "float: " << floatVal << "\n";
}
template<typename Integer>
typename std::enable_if<std::is_integral<Integer>::value>::type
func(Integer integer)
{
std::cerr << "integral: " << integer << "\n";
}
int main()
{
func(32.4246);
func(144532);
}
Live Example
Alternatively to overloading on return type like NathanOliver did, you can be a little more complicated in the template types:
template<typename Float, typename std::enable_if<std::is_floating_point<Float>::value>::type* = nullptr>
void func(Float floatVal)
{
std::cerr << "float: " << floatVal << "\n";
}
template<typename Integer, typename std::enable_if<!std::is_floating_point<Integer>::value && std::is_integral<Integer>::value>::type* = nullptr>
void func(Integer integer)
{
std::cerr << "integral: " << integer << "\n";
}
Live Demo
Notice that the second enable_if
for Integer
explicitly negates the enable_if
condition for Float
The benefit of this approach is that your functions still return void
And test it:
int main()
{
func(32.4246);
func(144532);
}
Output:
float: 32.4246
integral: 144532
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With