函数特化/重载规则示例
Function specialisation / overloading rules example
我知道你不能部分特化一个函数模板,我也理解典型的函数重载。
我需要帮助的是摸索以下 4 个 foo() 函数之间的区别。我希望其中一些是完全相同的东西的不同语法?
是否有知识渊博的人可以解释每个函数究竟发生了什么,它是模板特化还是重载,以及 c++ 编译器如何确定调用什么?
//(1)
template<typename T>
void foo(T t)
{
cout << "template<T> foo(T) " << endl;
}
//(2)
template<>
void foo<int*>(int* l)
{
cout << "template<> foo<int*>(int*) " << endl;
}
//(3)
template<typename T>
void foo(T* l)
{
cout << "template<T> foo(T*) " << endl;
}
//(4)
void foo(int* l)
{
cout << "normal overload foo(int*) " << endl;
}
int main()
{
int x = 0;
foo(x);
foo(&x);
return 0;
}
程序输出:
template<T> foo(T)
normal overload foo(int*)
评论中的解释:
// the 1st primary function template, overloaded function template
template<typename T>
void foo(T t)
// full template specialization of the 1st function template with T = int*
template<>
void foo<int*>(int* l)
// the 2nd primary function template, overloaded function template
template<typename T>
void foo(T* l)
// non-template function, overloaded function
void foo(int* l)
int main()
{
int x = 0;
foo(x); // only match the 1st function template; the others take pointer as parameter
foo(&x); // call the non-template function, which is prior to templates in overload resolution
return 0;
}
查看有关 overload resolution and explicit (full) template specialization 的更多详细信息。
让我们来看看第一个电话,foo(x)
。
int
不能写成指针,无法推导参数,next
void foo(int* l);
无法将 int
隐式转换为 int*
,接下来
template<typename T>
void foo(T t);
这似乎是一个很好的匹配,就像记住它作为 2)。下一个
template<>
void foo<int*>(int* l);
无法将 int
隐式转换为 int*
,接下来
template<typename T>
void foo(T* l)
因此,唯一可能的匹配项是 2),因此 template<T> foo(T)
是输出。
第二次通话,foo(&x)
。
void foo(int* l);
完美匹配x
类型的非模板函数。让我们记住这一点。
template<typename T>
void foo(T t);
好匹配!不过上一个还是比较好,下一个
template<>
void foo<int*>(int* l);
哦,之前模板的特化与类型完全匹配,这样更好,但是 1) 仍然是更好的匹配。下一个
template<typename T>
void foo(T* l)
比没有模板的专业化更好,但不比没有模板的模板好。
所以,最后调用了非模板函数。非模板总是优于模板。
foo(x)
的解析很容易发现,因为除了 template<typename T> void foo(T t)
之外没有其他候选函数。
所以我们的问题简化为:为什么 void foo(int* l)
调用 foo(&x)
?
- 调用模板方法
template<> void foo<int*>(int* l)
, 你需要调用 foo<int*>(&x)
template<typename T> void foo(T* l)
通过调用 foo<int>(&x)
template<typename T> void foo(T t)
通过调用 foo<int*>(&x)
如您所见,调用 foo(&x)
与上述三种显式模板调用方式都不匹配。
请注意,在没有专门函数 void foo(int* l)
的情况下,函数调用 foo<int*>(&x)
将由专门的 模板函数 template<> void foo<int*>(int* l)
解析击败非专业化的 模板函数 template<typename T> void foo(T t)
当试图确定重载时调用什么函数时,规则是:总是找到需要最少优化的函数来使用。
当用 int 调用 foo() 时,唯一可以使用的函数是第一个函数,因为您不能将 int 转换为 int*。
与 int* 一起使用时:
函数 4 无需任何优化即可使用。
函数 3 需要更改 T->int 以便 运行.
函数1需要将T改为指针类型,并确定T指向int。
函数 2 是函数 1 的特化
所以函数4可以立即使用,函数2需要更新模板类型,函数1,2需要更新模板类型和对象类型。
所以他们按顺序被调用:4 然后 3 然后 2 然后 1
我知道你不能部分特化一个函数模板,我也理解典型的函数重载。
我需要帮助的是摸索以下 4 个 foo() 函数之间的区别。我希望其中一些是完全相同的东西的不同语法?
是否有知识渊博的人可以解释每个函数究竟发生了什么,它是模板特化还是重载,以及 c++ 编译器如何确定调用什么?
//(1)
template<typename T>
void foo(T t)
{
cout << "template<T> foo(T) " << endl;
}
//(2)
template<>
void foo<int*>(int* l)
{
cout << "template<> foo<int*>(int*) " << endl;
}
//(3)
template<typename T>
void foo(T* l)
{
cout << "template<T> foo(T*) " << endl;
}
//(4)
void foo(int* l)
{
cout << "normal overload foo(int*) " << endl;
}
int main()
{
int x = 0;
foo(x);
foo(&x);
return 0;
}
程序输出:
template<T> foo(T)
normal overload foo(int*)
评论中的解释:
// the 1st primary function template, overloaded function template
template<typename T>
void foo(T t)
// full template specialization of the 1st function template with T = int*
template<>
void foo<int*>(int* l)
// the 2nd primary function template, overloaded function template
template<typename T>
void foo(T* l)
// non-template function, overloaded function
void foo(int* l)
int main()
{
int x = 0;
foo(x); // only match the 1st function template; the others take pointer as parameter
foo(&x); // call the non-template function, which is prior to templates in overload resolution
return 0;
}
查看有关 overload resolution and explicit (full) template specialization 的更多详细信息。
让我们来看看第一个电话,foo(x)
。
int
不能写成指针,无法推导参数,next
void foo(int* l);
无法将 int
隐式转换为 int*
,接下来
template<typename T>
void foo(T t);
这似乎是一个很好的匹配,就像记住它作为 2)。下一个
template<>
void foo<int*>(int* l);
无法将 int
隐式转换为 int*
,接下来
template<typename T>
void foo(T* l)
因此,唯一可能的匹配项是 2),因此 template<T> foo(T)
是输出。
第二次通话,foo(&x)
。
void foo(int* l);
完美匹配x
类型的非模板函数。让我们记住这一点。
template<typename T>
void foo(T t);
好匹配!不过上一个还是比较好,下一个
template<>
void foo<int*>(int* l);
哦,之前模板的特化与类型完全匹配,这样更好,但是 1) 仍然是更好的匹配。下一个
template<typename T>
void foo(T* l)
比没有模板的专业化更好,但不比没有模板的模板好。
所以,最后调用了非模板函数。非模板总是优于模板。
foo(x)
的解析很容易发现,因为除了 template<typename T> void foo(T t)
之外没有其他候选函数。
所以我们的问题简化为:为什么 void foo(int* l)
调用 foo(&x)
?
- 调用模板方法
template<> void foo<int*>(int* l)
, 你需要调用foo<int*>(&x)
template<typename T> void foo(T* l)
通过调用foo<int>(&x)
template<typename T> void foo(T t)
通过调用foo<int*>(&x)
如您所见,调用 foo(&x)
与上述三种显式模板调用方式都不匹配。
请注意,在没有专门函数 void foo(int* l)
的情况下,函数调用 foo<int*>(&x)
将由专门的 模板函数 template<> void foo<int*>(int* l)
解析击败非专业化的 模板函数 template<typename T> void foo(T t)
当试图确定重载时调用什么函数时,规则是:总是找到需要最少优化的函数来使用。
当用 int 调用 foo() 时,唯一可以使用的函数是第一个函数,因为您不能将 int 转换为 int*。
与 int* 一起使用时:
函数 4 无需任何优化即可使用。
函数 3 需要更改 T->int 以便 运行.
函数1需要将T改为指针类型,并确定T指向int。
函数 2 是函数 1 的特化
所以函数4可以立即使用,函数2需要更新模板类型,函数1,2需要更新模板类型和对象类型。
所以他们按顺序被调用:4 然后 3 然后 2 然后 1