为什么这个函数不能使用明显不同的签名进行重载?

6
以下代码由于“错误:重新定义‘template 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){}

但问题是,为什么我需要这样做呢?


问题在于你默认了第二个模板参数的模板类型。 - AndyG
你不能将另一个模板的默认参数赋给同一作用域内的其他声明。 - edmz
3个回答

5

N4527 §1.3.19 [defns.signature.templ]

函数模板签名定义

signature是指函数模板的名称、参数类型列表(8.3.5)、封闭命名空间(如有)、返回类型和模板参数列表。

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


4
您可以将std :: enable_if<...> :: type更改为函数的返回类型。据我所知,您无法将其传递给另一个模板参数的类型。
#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);
}

实时示例


如果这些函数是构造函数,那么这种方法将行不通(我的示例只是简化了问题,因为使用自由函数也可以重现该问题)。此外,这并不能回答“为什么”的问题。 - Ruslan

2

如果不像NathanOliver那样过度使用返回类型,你可以在模板类型中更加复杂:

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

在线演示
请注意第二个 enable_if 用于显式否定 Floatenable_if 条件。

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

并测试它:

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

输出:

float: 32.4246
integral: 144532

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接