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

时间:2011-05-13 03:20:42

标签: c++ templates overloading explicit-specialization

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

5 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:3)

主要区别在于:显式专业化根本不参与重载。

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&)参数同样匹配参数,但第二个函数是非模板函数因此最终是优选的。

答案 2 :(得分:3)

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

恕我直言,当您要使用显式模板参数调用该函数时,应使用function template的显式特化。 e.g。

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

在其他情况下,您应始终使用常规专业化。 e.g。

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

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

相关问题