简体   繁体   English

重载模板函数时显式特化和常规函数之间的区别

[英]Difference between explicit specialization and regular functions when overloading a template function

I'm on a roll today. 我今天开始了。 Here goes n00b question number 7: 这里是n00b问题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;
}

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 . 如果您要在不是模板函数的头文件中声明和定义函数,则必须将该函数声明为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. 如果链接器没有这样做,那么每当.cpp文件包含头文件时,链接器就会抱怨函数的重复定义。 Using the inline 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 the inline function in the header file, and avoids the overhead of a function call with an associated stack active record setup and clean-up. 在非模板函数上使用inline关键字在编译器级别具有类似的效果,因为无论何时在.cpp文件中使用该函数,编译器都会使用inline函数中的函数代码的主体替换该函数调用。在头文件中,并避免使用相关堆栈活动记录设置和清理的函数调用的开销。 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. 您不能重载函数的返回类型。

A major difference is: Explicit specializations don't participate in overloading at all. 一个主要的区别是:显式专业化根本不参与重载。

template<typename T> void f(T const&);
template<> void f<char const*>(char const * const&);

Calling with f("hello") will not consider any explicit specializations. f("hello")调用不会考虑任何明确的特化。 It will only take all templates, and deduce their template arguments. 它只会获取所有模板,并推断出它们的模板参数。 The above T will be deduced to char[6] , and so the specialization won't be selected. 上面的T将推导为char[6] ,因此不会选择专业化。

If you overload the function template instead, you have completely different characteristics. 如果改为重载函数模板,则具有完全不同的特征。

template<typename T> void f(T const&);
void f(char const * const&);

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. 调用它,它将选择第二个函数,因为生成的特化的(char const(&)[6])参数和(char const * const&)参数同样匹配参数,但第二个函数是非-template函数,因此最终是优选的。

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. 当编译器遇到函数调用时,它首先查找非模板函数definiton,然后查找显式专用模板,最后查找其签名与函数调用匹配的模板定义。 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. 恕我直言,当你要使用显式模板参数调用该函数时,应该使用function template显式特化。 eg 例如

test<int>(myClass); // no argument for 'int' -> declare test() as template specialization

In other cases, you should always use normal specialization. 在其他情况下,您应始终使用常规专业化。 eg 例如

test(10, myClass); // argument 10 is 'int' -> test() should be normal specialized

Technically there is no difference between normal and explicit template specialization of a function. 从技术上讲,函数的正常和显式模板特化之间没有区别。 The normal specialized versions are completely independent of template functions. 普通的专用版本完全独立于template功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM