2014-12-03 43 views
7

假设以下几点:带重载的显式模板函数专业化:为什么要这样做?

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

当引入一个基本模板也具有过载的显式专业化,专业化不被设计过载解析期间考虑。我明白这一点。

但是,鉴于我可以让#3成为非模板重载,然后将其视为重载解析,为什么我仍然想按照上面所做的那样做?上面演示的设置是否有一个有效的用例?我能想到的唯一情况是,如果您不依赖模板类型推演,则无法使用非模板函数,因为当您调用它们时,它们不会接受<>语法。

顺便说一句我只查看了C++ 03的规则。我不确定C++ 11是否会/如何更改这些规则/行为。

+4

必读:[GotW#49 - 模板专业化和超载](http://www.gotw.ca/gotw/049.htm) - TL; DR不要这样做。 – sehe 2014-12-03 20:20:45

+1

这不是重复的。我在问你什么时候会使用显式函数专门化和重载。或者,如果不应该这样做。链接问题的答案不能解决这个问题。 – 2014-12-03 20:24:29

+2

也许你的代码中有一个基于非模板的foo,它需要一个int *。添加模板专业化意味着你可以是明确的,并使用foo (&i); – cppguy 2014-12-03 21:04:55

回答

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(显式实例化是一样的隐式调用)。

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。这意味着我们可以专门为z.cpp中的其他类型专门设置foo,而无需更改y.cpp

随着#4,你必须更新y.cpp每当你添加一个新的过载。

+0

我99%肯定这样的代码违反了一个定义规则,因此这是未定义的行为 – 2014-12-04 15:11:51

+0

@MarkB - 为什么?定义只在'z .cpp'。 – tohava 2014-12-05 08:40:42