2012-08-01 62 views
4

我不知道为什么模板专业化有意义?为什么要使用模板专业化?

下面的东西不是等价的吗?

模板专业化:

template <typename T> 
void f(T t) { 
    something(t); 
} 

template <> 
void f<int>(int t) { 
    somethingelse(t); 
} 

非模板函数,而不是专业化:

void f(int t) { 
    somethingelse(t); 
} 

我相信这些是相同的,因为非模板函数将始终是首选。

+0

您正在专门讨论* function *模板专业化。这些被认为是弃用和糟糕的风格。类模板的专业化非常有意义。 – Xeo 2012-08-01 11:29:26

+0

哦,这很有趣。你能提供一个链接吗?快速搜索没有任何结果。 – Sarien 2012-08-01 11:31:30

+0

http://www.gotw.ca/publications/mill17.htm – interjay 2012-08-01 11:34:26

回答

3

问题归结为确定什么时候使用专门化,超载不能。在这种情况下,虽然它们不够普遍,但存在不同情况,并且很容易出现错误,因此一般建议是将重载更改为专业化。

  • 当调用者显式地请求使用模板时。在您提供的代码示例中,如果调用为f<int>(42)或甚至f<42>(),则不会使用超载。

  • 如果您无法提供所需的重载,或者无法在呼叫地点解决超载问题。例如,如果类型不是函数参数(它或者是不或仅在返回类型签名本之一:

    模板 五六();

在这种情况下,您不能提供过载int f();double f();,但您可以根据需要提供尽可能多的模板特化,并且由用户决定是否强制选择其中一个。请注意,这可以被视为以前的子项案例:因为模板参数不参与函数参数,所以用户需要提供模板参数,所以调用明确指向模板。

  • 当你想放置的参数的组合特殊的限制和抑制的隐式转换:

    模板 无效F(T,T); //两个参数必须是同一类型

因为模板参数推导只进行完美的匹配,该模板只能当两个参数都完全相同的类型的使用,如果添加过载void f(int,int)那过载可以用于隐式转换为int的类型的任意组合,如f(5, 3.0),但专业化不会。

一般来说,对于大多数情况,上述情况都不适用,因此应该优先选择超载。


可能有更多,但这些都是我能回忆起了我的头顶部

+0

我们对这个主题有一个最近的讨论,请参阅这个问题的答案的评论:http://stackoverflow.com/questions/11034759 – Gorpik 2012-08-01 13:05:05

+0

@Gorpik:我刚刚读过它们(粗略阅读了评论),你想提出什么? – 2012-08-01 13:15:57

+0

讨论的一部分讨论了使用专门化是否有效作为为调用者提供更干净的接口的方法。这与你所建议的原因相似。并不是所有人都同意:有些人从未使用过功能模板专业化。 – Gorpik 2012-08-03 12:36:05

4

这是我想出了答案:

这是不同的,如果模板参数不是正在定义的函数的参数:

template <typename T> 
void f() { 
    T t; 
    something(t); 
} 

template <> 
void f<int>() { 
    int t; 
    somethingelse(t); 
} 

在这种情况下定义:

void f() { 
    int t; 
    somethingelse(t); 
} 

会使所有的模板版本不可用。

也许别人有更好的想法。 :)

+1

这基本上是我的推理。如果你在模板中使用这个函数,并且你需要得到正确的函数,你可以称它为'f ()'。哪些不会发现过载。 – 2012-08-01 11:35:03

+0

f ()的编码方式与the_other_f()基本相同。如果你喜欢尖括号,会对你有所帮助。由于局部特化不适用于函数模板,我也认为应该使用重载而不是显式的特化 – 2012-08-01 11:49:52

3

如果您坚持将它称为f<int>(42),则您声明函数的方式确实如此。这将找到专业化,但不会超负荷。

如果该呼叫总是看起来像f(42),则可以采用其他方法。

0

函数模板专业化支持函数重载弃用有一个例外:你被允许添加函数模板专门化到std名称空间,您不允许添加新函数。因此,如果您需要为std命名空间中的某个东西提供特定版本,则必须使用模板特化。例如,要支持用用户定义的类创建一个unordered_map作为键,你必须专门为你的类设置std :: hash。