带有重载的显式模板函数特化:你为什么要这样做?

时间:2014-12-03 20:18:13

标签: c++ templates c++11

假设以下内容:

template <typename T> void foo (T*);   // #1
template <typename T> void foo (T);    // #2
template <> void foo (int*);           // #3

在引入具有重载的基本模板的显式特化时,在设计过载解析期间不考虑特化。我理解这一点。

但是,鉴于我可以使#3成为一个非模板重载并且它会被考虑用于重载解析,为什么我仍然想要像上面那样做呢?上面说明的设置是否有一个有效的用例?我唯一能想到的是,如果你不依赖于模板类型推导,那么非模板函数就无法使用,因为当你调用它们时它们不会接受<>语法。

BTW我只审查了C ++ 03的规则。我不确定C ++ 11是否/如何改变这些规则/行为。

2 个答案:

答案 0 :(得分:1)

#3可用于在一个编译单元中专门化模板函数,而无需更新其他编译单元。

假设我们z.cpp看起来像这样:

template <class T> void foo (T*) { puts("1"); }
template <class T> void foo (T) { puts("2"); }
template <> void foo (int*) { puts("3"); }
void foo(int*) { puts("4"); }

int dummy() {
    foo((int*)NULL);    
    foo<int>((int*)NULL);
    foo(4);    
    foo((long*)NULL);    
}

y.cpp看起来像这样:

#include <stdio.h>

template <class T> void foo (T*);
template <class T> void foo (T);

int main() {
    foo((int*)NULL);    
    foo<int>((int*)NULL);
    foo(4);    
    foo((long*)NULL);    
}

主要的第一行将引用#3而不是#4。这意味着我们可以foo专门针对z.cpp中的其他类型,而无需更改y.cpp

使用#4,每次添加新的重载时都必须更新y.cpp

答案 1 :(得分:1)

基本上,我倾向于专业化以避免最不意外的原则。您希望允许显式或非显式地调用函数以支持尽可能多的代码中的使用...并且在显式实例化时,它应该与不存在时的行为相同。

以下模板函数是您可能希望如何显式选择要调用的函数的示例(尽管所有3个函数都使用相同的参数)。

template <typename T> void foo (T*){std::cout << 1 << std::endl;}   // #1
template <typename T> void foo (T){std::cout << 2 << std::endl;}    // #2
template <> void foo<int> (int* x){std::cout << 3 << std::endl;}    // #3
//void foo (int*){std::cout << 3 << std::endl;}           // #3

template <typename T>
void bar(void* x) {
   foo<T>(reinterpret_cast<T*>(x));
   foo<T*>(reinterpret_cast<T*>(x));
   foo(reinterpret_cast<T*>(x));
}


int main()
{
   cout << "Hello World" << endl; 
   bar<int>(NULL);
   return 0;
}

如果没有专门化,则输出1,2,3(显式实例化的调用与重载的调用不同),而使用特化则获得3,2,3(显式实例化与隐式调用相同)

相关问题