Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't this function be overloaded with one of clearly different signature? [duplicate]

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?

like image 766
Ruslan Avatar asked Jul 28 '15 12:07

Ruslan


3 Answers

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.

like image 198
cpplearner Avatar answered Nov 11 '22 09:11

cpplearner


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

like image 25
NathanOliver Avatar answered Nov 11 '22 10:11

NathanOliver


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
like image 2
AndyG Avatar answered Nov 11 '22 08:11

AndyG