Why can't this function be overloaded with one of the clearly different signatures?

The following code could not compile due to 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 obviously have different signatures when instantiating. So why is it impossible to compile?

Pay attention . I know how to fix this: simply adding another layout template parameter to one of the functions, for example. typename=void , will work as here

 template<typename Integer, typename dummy=void, typename = typename std::enable_if<std::is_integral<Integer>::value>::type> void func(Integer integer){} 

But why should I do this?

+6
source share
3 answers

N4527? 1.3.19 [defns.signature.templ]

signature

<function template> name, list of parameter types (8.3.5), covering the namespace (if any), return type and list of template parameters

The default template argument is not part of the function template signature.

+5
source

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

Living example

+4
source

As an alternative to overloading by return type, such as NathanOliver , you may be a bit more complicated in the types of templates:

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

Demo version
Note that the second enable_if for Integer explicitly negates the enable_if condition for Float

The advantage 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 
+2
source

All Articles