模板函数中不会自动将`int`转换为`float`。

13

我在用C++编程数年后,今天被问了一个简单的问题,但是实际上我找不到答案,所以来这里寻求帮助。

除了想知道为什么会出现这个错误之外,我还想知道如何通过修改只有模板函数而不改变main()函数的情况下解决以下错误。

template <class T>
T Add(T first, T second)
{
    return first + second;
}

int main()
{
    auto sample_1 = Add(1, 2); // Works
    auto sample_2 = Add(1.f, 2.f); // Works
    auto sample_3 = Add(1.f, 2); // Error: no instance matches the argument types: (double, int)
    return 0;
}

3
引入 class T2 或使用 decltype(first) second 使 second 不可推导? - Piotr Skotnicki
虽然很有趣,但我认为应该实现一个默认编译器开关来处理这种情况... - sjsam
6个回答

16
除了想知道为什么会出现这个错误,当你调用 Add(1.f, 2)函数时,第一个参数的类型是float,第二个参数的类型是int。编译器必须将第一个参数转换为int或将第二个参数转换为float。由于两者都需要转换,它们是同样好的选择,不能优先选择一个。我想知道如何通过修改模板函数来解决下面的错误。你可以将函数模板更改为:
template <class T1, class T2>
auto Add(T1 first, T2 second)
{
    return first + second;
}

或者(感谢@PiotrSkotnicki):
template <class T>
T Add(T first, decltype(first) second)
{
    return first + second;
}

在这种情况下,second的类型并不是从传递给函数的参数中推断出来的。而first的类型则是根据第一个参数推导出来的,并且second的类型被强制与first的类型相同。
Add(1.2f, 2);  // The first argument is deduced to be float
               // The second argument is forced to be float.

Add(2, 1.2f);  // The first argument is deduced to be int
               // The second argument is forced to be int.

2
当 Piotr 的评论被删除时,你应该解释一下那个神奇的第二个例子是如何工作的。 - Lightness Races in Orbit

9

只需这样做:

template <class T1, class T2>
auto Add(T1 first, T2 second)
{
    return first + second;
}

与唯一的 T 类似,它既被推断为 int,又被推断为 double...

4
当你需要
template <class T>
T Add(T first, T second)

首先,firstsecond的类型需要相同。如果您想使用两种不同的类型,则可以添加第二个模板参数。

template <class T1, class T2>
auto Add(T1 first, T2 second)

或者对于C++11。
template <class T1, class T2>
auto Add(T1 first, T2 second) -> decltype(first + second)

1
T未声明,因此无法用作返回类型。正确编写返回类型,然后说明T1T2不同是可能的,但这足够复杂(除非像其他答案中使用auto),以至于您的答案可能需要解决这个问题才能对OP真正有用。 - user743382

3
编译器试图推导出可用于创建与签名匹配的函数的模板类型。由于参数是不同的类型,因此无法完成推导。
您可以显式指定类型:
auto sample_3 = Add<float>(1.f, 2);

但是你说你不想这样做。

你可以更改函数以使用两种模板类型:

template <class T1, class T2>
T1 Add(T1 first, T2 second)
{
    T1 p;
    p = first + second;
    return p;
}

但现在你必须做出一个关于返回哪种类型的假设。

我从未尝试过使用auto作为返回类型,但显然它可以工作:http://ideone.com/1qO95w

template <class T1, class T2>
auto Add(T1 first, T2 second)
{
    auto p = first + second;
    return p;
}

谢谢您的回答。请注意,您的代码中T未定义。 - Emadpres
@Emadpres 谢谢,那只是一个简单的复制/粘贴错误。我还用 auto 补充了答案。 - Mark Ransom
这是一个我无法使用的新的C++14特性。不管怎样,非常感谢您的努力,我给您点赞 +1 :] - Emadpres
返回哪种类型?显然是decltype(first+second)。或者你可以明确地写出来。 - Random832

2

为什么要写自己的函数,当标准库已经提供了它们呢?

在 C++11 中,您可以使用:

#include <functional>
int main()
{
    auto sample_1 = std::plus<float> () ( 1, 2 ); // Works
    auto sample_2 = std::plus<float> () ( 1.f, 2.f ); // Works
    auto sample_3 = std::plus<float> () ( 1.f, 2 ); // Works
    return 0;
}

在C++14中:

#include <functional>
int main()
{
    auto sample_1 = std::plus<> () ( 1, 2 ); // Works
    auto sample_2 = std::plus<> () ( 1.f, 2.f ); // Works
    auto sample_3 = std::plus<> () ( 1.f, 2 ); // Works
    return 0;
}

1

我想知道我如何通过修改模板函数来解决以下错误

就像这样:

template <class T1, class T2>
T1 Add(T1 first, T2 second)
{
    T1 p;
    p = first + second;
    return p;
}

int main()
{
    auto sample_1 = Add(1, 2);
    auto sample_2 = Add(1.f, 2.f);
    auto sample_3 = Add(1.f, 2);
    return 0;
}

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