关于函数模板实例化的c++规则



我正在学习函数模板,我想研究一下函数模板实例化的一些规则。所以我写了下面的代码:

#include <iostream>
template <typename>
int check(int x) {
  return x * 2;
}
int main() {
  std::cout << check<double>(10) << std::endl; // #1
  std::cout << check<>(10) << std::endl;         // #2
  std::cout << check(10) << std::endl;            // #3
  return 0;
}

#1、#2和#3行没有一起编译,每次尝试我只留下其中一行,并注释其余的。因此,当启用#1时,我没有编译错误,并且打印了正确的答案"20"。据我所知,"check<"double">"调用模板实例化机制,所以"函数被真正创建(模板参数的类型没有任何影响)。当#3启用时,我有一个编译错误"错误:没有匹配的函数来调用'check(int)'",这是合理的,因为我试图调用"check(int) "函数不存在。我的问题是关于#2的情况:在这种情况下,我得到相同的"错误:没有匹配的函数调用'check(int)'"。不应该调用"check<>(10)触发模板实例化机制?

不要在<>中放置任何模板参数。编译器如何知道实例化哪个模板函数?请注意你的模板函数是:

template <typename>
int check(int x) 

如果你把它改成这样:

template <typename T>
int check(T x) 

then check<>(10)应该没问题,因为编译器可以从参数中知道类型。

我不得不说通常模板不会那样做:(

试试这个:

template<typename T>
T check(T x){
    return x*2;
}

您将获得的唯一模板实例化是使用

check<double>(10)

其他的不实例化模板。此外,要获得函数模板的全部功能,请将template参数包含为

template<typename T>
T check(T x) {
  return x*2;
}

然后使用模板参数演绎的力量,你可以调用

check(10.0);   // instantiates check<dobule>
check(3);      // instantiates check<int>

a = MyObject();
check(a);         // instantiates check<MyObject>

#2在模板参数可以推导的情况下是有效的。

#include <iostream>
template <class T>
void foo(T t)
{
    std::cout << "Template " << t << 'n';
}
void foo(int n)
{
    std::cout << "Not template " << n << 'n';
}
int main()
{
    foo(10); //calls non-template function 
             //because matching non-template preferred over function templates
    foo<>(10); //calls the template function, empty brackets indicate you want
               //the template overload, type is deduced from passed argument.
}

另一种可能,如果函数模板有默认实参(仅在c++ 11中合法)。

template <class T = void>
int foo()
{
    return 10;
}
int main()
{
    return foo<>(); //same as foo<void>();
}

如果你不传递模板参数,这相当于寻找没有模板参数的函数(即它没有实例化模板)。在这种情况下,添加的<>没有任何意义,因为没有超载。

因为你的函数实际上没有使用模板做任何事情,编译器因此不能推断类型T,但是如果你这样写:

template <typename T>
T check(T x) {
    return x * 2;
}

那么所有3种情况将工作,因为它推断类型T。详见https://stackoverflow.com/a/797632/888641

注意:您可以使用typenameclass,它们在这里做完全相同的事情。

最新更新