2011-03-28 73 views
5

请看下面的测试代码:选择具有指针参数

template<class T> struct Wrap {}; 

template<typename T> inline 
void fun (T *&Int)   // **choice 1** 
{} 

template<typename T> inline 
void fun (Wrap<T> *&Int) // **choice 2** 
{} 

int main() 
{ 
    int i = 6; 
    fun((char*&)(i));   // **call 1** 
    fun((Wrap<char>*&)(i)); // **call 2** 
} 

当我运行在Linux G ++这段代码,它的工作原理按预期。当使用char * &调用fun()时,它会直接调用choice 1的函数。然而,当我们调用fun()与包装< char> * &并且它调用了选项2时,我感兴趣。尽管选项1和2对于第二次调用都有效,编译器仍然设法选择一些更好的竞争者 - > choice 2(因为它存在)。

问题:是否保证,对于任何其他C++编译器都会保留相同的行为?如果不是,那么是否有其他选择使其具有确定性?

+0

'inline'在模板函数中几乎没有用处。这不是必须的,因为它们是(非专用的)模板,因此不会导致链接器错误,编译器比我们更好地确定何时内联和何时不内...并可能完全忽略您的请求。 – 2011-03-28 09:12:43

回答

2

虽然代码可能看起来像一个模板专业化,事实并非如此。该语言不允许部分模板功能专业化。这两个是不相关的模板,恰巧是重载。

编译器将调用查找高达fun((Wrap<char>*&) i)与通常的查找机制,会发现两个模板,并确定有两个潜在的重载:然后

template <typename T> void fun(T*&);  // with T == Wrap<char> 
template <typename T> void fun(Wrap<T>*&) // with T == char 

重载决策将决定第二个是更好的匹配并实例化它。这是由标准保证的,但要注意:它们不是相同的模板,而是不同的模板,可能会遇到未预期的结果。看文章@LiKao链接更多的见解。

3

对规范有更好的了解的人可以证实这一点,但我相信Wrap<T>是一个比简单T更具体的类型,在所有平台编译器上,call 2总是会解决为'choice 2'。

+1

除非有编译器的bug;) – 2011-03-28 07:32:22

+0

编译器bug!?从来没有听说过一个...... :) – 2011-03-28 21:55:14

6

选择第二选择,因为它比那是第一代更加专业化,T*&可以绑定到任何非临时T*,但Wrap<T>*&只能绑定到一个非暂时性的Wrap<T>*。就我所知,这是标准的,应该是可移植的行为,但在实践中,什么是和什么是不可移植的,对于这类事情通常不是什么标准的定义。

+3

它实际上是可移植的,但它们不是模板的特化,而是两个分开的模板,它们恰好是重载。 – 2011-03-28 08:06:06

1

有一件事情可能使这个问题变得更加严重,专业模板类和模板函数的规则差异很大。这是为了重载模板函数的可能性,而不能重载类。因为我不是对这个话题如此坚定我只是链接到的人谁是能够解释更深入:

Herb Sutter: "Why Not Specialize Function Templates?"

+1

这不是专业化,而是过载。专业化将有一个模板参数列表出现在函数标识符和函数参数之间(以及在模板之后出现的空模板参数列表,因为函数特化必须是完全专业化的)。 – 2011-03-28 09:11:15