当使用函数调用模板函数时,我的调用会遇到一个意外的匹配模板函数

When using function calls to template functions, I am faced with an unexpected matching template function for my call

本文关键字:函数 一个 意外 调用 函数调用 我的 遇到      更新时间:2024-09-24

对于以下代码,为什么编译器将我的函数调用与(意外的(模板函数匹配:

首先这里是可用的功能模板:

// First function template
template <typename T, typename U>
auto sub(T x, U y) {
return x - y;
}
// Second function template
template <typename T>
auto sub(T x, T y) {
return x - y;
}

现在让我们假设我从一个模板参数推导语句开始:

sub(5.2, 2.1);

上面的语句应该使用上面提供的第二个函数模板来实例化一个函数实例(模板函数(,并且最终看起来像这样:

template<>
double sub<double>(double x, double y) {
return x - y;
}

下一条语句不会实例化新的模板函数,因为它可以与之前创建的模板函数匹配。

sub<double>(2.3, 234.2);

现在,下面的语句是我有点困惑的地方。

sub<double>(2.3, 234.0f); // Weird one

尽管我提供了一个单一的实际类型(double(,但在模板参数中,我面临着一个奇怪的结果。我有目的地将第二个函数参数设置为浮点,以使其不完全匹配我们前面提到的函数实例(模板函数(,并期望浮点升级,使浮点升级为双精度,然后匹配模板函数,但最终并不是这样。。。但是,它使用顶部提供的第一个函数模板创建了一个新的函数实例(模板函数(,结果如下:

template<>
double sub<double, float>(double x, float y) {
return x - y;
}

我感到困惑的是,我怎么认为编译器更喜欢升级而不是这样的东西,或者我可能把它和其他东西混淆了,我希望有人能澄清一下。

同样困扰我的一个问题是,我不知道如何才能显式调用我真正想要的模板函数,例如:

sub<double>(2, 2);

如果我想让它调用两个参数类型都是double的模板函数,并且只想让我的两个参数从int数字转换为double,该怎么办。按照这个逻辑,我将无法做到这一点,因为编译器最终会创建一个新的函数实例(模板函数(,看起来像这样:

template<>
double sub<double, int>(double x, int y) {
return x - y;
}

我必须提到的是,我并不是在谈论如何转换我的论点,因为我非常清楚我可以在它们上使用static_cast,我也不是在谈论做这样的事情:

sub<double, double>(2, 2);

当然,使用第一个函数模板创建一个新的函数实例(模板函数(,而不是使用已经可用的模板函数(通过使用第二个函数模板创建(。有人能解释一下,如果真的有办法的话,我该怎么做吗?所有这些,主要是因为我试图真正理解概念。

您可以提供模板参数的部分列表。例如,如果你有

template <typename A, typename B, typename C>
void foo(A, B, C);

然后这些呼叫

foo(1,2,3);
foo<int>(1,2,3);
foo<int, double>(1,2,3);
foo<int, double, float>(1,2,3);

都很好。

因此,sub<double>(2.3, 234.2f);仍然与第一个函数模板和第二个模板的实例化相匹配,前一个模板更匹配,因为它不需要转换。只有当两个匹配都一样好时,重载解析才更喜欢非模板而不是模板1。如果模板更匹配,则使用它。

当两个参数不具有相同类型时,可以强制选择第二个模板:

auto x = (static_cast<float(*)(float, float)>(sub))(1, 2.0);

但这当然违背了目的。为了方便使用,您需要引入一些其他选择机制,例如

enum class same { type };
template <typename T, same = same::type>
auto sub(T x, T y)...
... sub<double, same::type>(2.3, 234.0f) ...

1或者更确切地说,需要推导模板参数的调用与不需要推导任何参数的调用。

相关文章: