繁体   English   中英

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

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

我今天开始了。 这里是n00b问题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;
}

显式专用模板函数和非模板常规函数之间没有区别,除了当编译器为函数调用寻找匹配的签名类型时,它将首先选择匹配的非模板函数在尝试实例化可能满足所需签名匹配的任何可用模板函数之前所需的签名。

如果您要在不是模板函数的头文件中声明和定义函数,则必须将该函数声明为inline函数。 这是因为模板函数不是与代码模块链接的实际函数,直到它实际被实例化为止。 然后链接器在编译代码模块后抛弃该实例化。 如果链接器没有这样做,那么每当.cpp文件包含头文件时,链接器就会抱怨函数的重复定义。 在非模板函数上使用inline关键字在编译器级别具有类似的效果,因为无论何时在.cpp文件中使用该函数,编译器都会使用inline函数中的函数代码的主体替换该函数调用。在头文件中,并避免使用相关堆栈活动记录设置和清理的函数调用的开销。 因此,链接器不会抱怨函数的重复定义。

我不是专家,但是当我想定义不同的返回类型时,我的经验是使用模板(和专业化)。 您不能重载函数的返回类型。

一个主要的区别是:显式专业化根本不参与重载。

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

f("hello")调用不会考虑任何明确的特化。 它只会获取所有模板,并推断出它们的模板参数。 上面的T将推导为char[6] ,因此不会选择专业化。

如果改为重载函数模板,则具有完全不同的特征。

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

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

当编译器遇到函数调用时,它首先查找非模板函数definiton,然后查找显式专用模板,最后查找其签名与函数调用匹配的模板定义。 因此,例如,如果您有明确定义的模板和模板,那么编译器将用于明确定义的模板。 因此,当您希望以与模板处理它的方式不同的方式处理特定数据类型时,应使用明确的特殊模板。

显式特化的另一个用途是当你想要“重载”一个不带任何参数的函数时。 您可以使用显式特化来为函数提供不同的定义以处理不同的数据类型。

恕我直言,当你要使用显式模板参数调用该函数时,应该使用function template显式特化。 例如

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

在其他情况下,您应始终使用常规专业化。 例如

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

从技术上讲,函数的正常和显式模板特化之间没有区别。 普通的专用版本完全独立于template功能。

暂无
暂无

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

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