重载模板函数时显式特化和常规函数之间的区别
我今天很开心。这里是第 7 号问题:
当您尝试重载模板函数时,显式专业化和普通函数之间有什么区别?
什么情况下适合使用显式专业化?我不太明白:
#include <iostream>
template <typename s> void test(s var1);
template <> void test<int>(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
template <> void test<int>(int var1){
std::cout << "int " << var1 << std::endl;
}
相反:
#include <iostream>
template <typename s> void test(s var1);
void test(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
void test(int var1){
std::cout << "int " << var1 << std::endl;
}
I'm on a roll today. Here goes n00b question number 7:
What's the difference between explicit specialization and just regular functions when you try to overload a template function?
What's the appropriate situation to use the explicit specialization? I don't quite understand it:
#include <iostream>
template <typename s> void test(s var1);
template <> void test<int>(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
template <> void test<int>(int var1){
std::cout << "int " << var1 << std::endl;
}
As oppose to:
#include <iostream>
template <typename s> void test(s var1);
void test(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
void test(int var1){
std::cout << "int " << var1 << std::endl;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
显式专用模板函数和非模板常规函数之间确实没有区别,除了当编译器为函数调用查找匹配的签名类型时,它会首先选择一个匹配的非模板函数在尝试实例化任何可能满足所需签名匹配的可用模板函数之前,先获取所需的签名。
如果您要在头文件中声明和定义一个函数,但该函数不是模板函数,则必须将该函数声明为内联函数。这是因为模板函数在实际实例化之前并不是与代码模块链接的实际函数。然后,链接器在编译代码模块后丢弃该实例化。如果链接器不这样做,那么每次 .cpp 文件包含头文件时,链接器都会抱怨函数的重复定义。在非模板函数上使用
inline
关键字在编译器级别具有类似的效果,因为每当在 .cpp 文件中使用该函数时,编译器都会将该函数调用替换为头文件中内联函数的函数代码,并避免了函数调用与关联堆栈活动记录设置和清理的开销。因此,链接器不会抱怨函数的重复定义。There really isn't a difference between an explicitly specialized template function and a non-template regular function other than the fact that when the compiler looks for a matching signature type for the function call, it will first pick a non-template function that matches the required signature before trying to instantiating any available template functions that may fulfill the required signature match.
If you are going to declare and define a function inside a header file that is not a template-function though, you will have to declare the function as
inline
. That is because a template function is not an actual function that is linked with a code module until it is actually instantiated. The linker then throws away that instantiation after compiling the code module. If the linker did not do this, then every time a .cpp file included the header file, the linker would complain about duplicate definitions for a function. Using theinline
keyword on a non-template function has a similar effect at the compiler level, in that any time the function is used in a .cpp file, the compiler replaces that function call with the body of the function code from theinline
function in the header file, and avoids the overhead of a function call with an associated stack active record setup and clean-up. Therefore the linker won't complain about duplicate definitions for a function.我不是专家,但我的经验是当我想定义不同的返回类型时使用模板(和专业化)。您不能重载函数的返回类型。
I'm not an expert, but my experience is to use templates (and specialization) when I want to define different return types. You can't overload the return type of a function.
主要区别是:显式专业化根本不参与重载。
使用
f("hello")
调用不会考虑任何显式特化。它只会获取所有模板,并推断出它们的模板参数。上面的T
将被推导为char[6]
,因此不会选择专业化。如果您重载函数模板,则会具有完全不同的特征。
调用此函数时,它将选择第二个函数,因为生成的特化的
(char const(&)[6])
参数和(char const * const&)
code> 参数与参数同样匹配,但第二个函数是非模板函数,因此最终首选它。A major difference is: Explicit specializations don't participate in overloading at all.
Calling with
f("hello")
will not consider any explicit specializations. It will only take all templates, and deduce their template arguments. The aboveT
will be deduced tochar[6]
, and so the specialization won't be selected.If you overload the function template instead, you have completely different characteristics.
Calling this, it will select the second function, because both the
(char const(&)[6])
parameter of the generated specialization and the(char const * const&)
parameter match the argument equally well, but the second function is a non-template function, hence it is preferred eventually.当编译器遇到函数调用时,它首先查找非模板函数定义,然后查找显式专用模板,最后查找签名与函数调用匹配的模板定义。
因此,例如,如果您有一个显式定义的模板和一个模板,那么编译器将采用显式定义的模板。因此,当您想要以与模板处理方式不同的方式处理特定数据类型时,应该使用显式专用模板。
显式专业化的另一个用途是当您想要“重载”不带任何参数的函数时。您可以使用显式专业化为函数提供不同的定义以处理不同的数据类型。
When the compiler comes across a function call, it first looks for a non-template function definiton, then an explicitly specialized template and finally, a template definition whose signature matches with the function call.
So, for example, if you have an explicitly defined template and a template, then the complier goes for the explicitly defined template. Therefore, you should use an explicity specialzed template when you want to handle a particular datatype in a different manner from the way the template would have handled it.
Another use for explicit specialization is when you want to "overload" a function that does not take any arguments. You can use explicit specialization to give different definitions to the function to handle different datatypes.
恕我直言,当您要使用显式模板参数调用该函数时,应该使用函数模板的显式专业化。例如
,在其他情况下,您应该始终使用正常的专业化。例如,
从技术上讲,函数的正常模板特化和显式模板特化之间没有区别。普通的专用版本完全独立于
模板
功能。IMHO, explicit specialization for
function template
should be used when, you are going to call that function using explicit template argument. e.g.In other cases, you should always use normal specialization. e.g.
Technically there is no difference between normal and explicit template specialization of a function. The normal specialized versions are completely independent of
template
functions.