14

我今天很开心。这里是 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;
}
4

5 回答 5

6

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

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

于 2011-05-13T03:28:03.933 回答
3

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

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

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

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

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

调用它,它将选择第二个函数,因为(char const(&)[6])生成的特化的(char const * const&)参数和参数都很好地匹配参数,但是第二个函数是非模板函数,因此最终首选。

于 2011-05-13T10:09:05.727 回答
3

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

于 2012-07-21T00:12:48.657 回答
1

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

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

于 2017-12-09T20:10:31.517 回答
0

恕我直言,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功能。

于 2011-05-13T03:31:08.057 回答