为什么这个函数不能用明显不同的签名之一重载?

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

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

但这两个函数显然在模板实例化上具有不同的签名。那为什么不能编译呢?

请注意:我确实知道如何解决这个问题:只需向其中一个函数添加另一个虚拟模板参数,例如typename=void,会像这里一样工作

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

但问题是为什么我必须这样做?

您可以将 std::enable_if<...>::type 更改为函数的 return 类型。据我所知,您不能将它传递给另一个模板参数的类型。

#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

或者像 那样重载 return 类型,你可以在模板类型中稍微复杂一点:

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
请注意,Integer 的第二个 enable_if 明确否定了 Float

enable_if 条件

这种方法的好处是您的函数仍然 return void

并测试它:

int main()
{
    func(32.4246);
    func(144532);
}

输出:

float: 32.4246
integral: 144532

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

默认模板参数不是函数模板签名的一部分。