使用指针参数在模板实例化之间进行选择

时间:2011-03-28 06:00:57

标签: c++ templates compiler-construction

查看以下测试代码:

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 *&amp;来调用fun()时,它会直接调用选择1的函数。 但是,当我们用Wrap&lt;来调用fun()时,我感兴趣char&gt; *&amp;它调用了选择2.即使选择1和2都对第二次调用有效,编译器设法选择更好的竞争者 - &gt;选择2(因为它存在)。

问题:是否可以保证,对于C ++的任何其他编译器都会保留相同的行为?如果没有,那么还有其他方法可以确定它吗?

4 个答案:

答案 0 :(得分:6)

选择第二个选项是因为它比第一个选择更专业,即T*&可以绑定到任何非临时T*,但Wrap<T>*&只能绑定到非临时Wrap<T>*。据我所知,这是标准的,应该是可移植的行为,但在实践中,当涉及到这类事物时,实际上是不可移动的,通常不是什么标准的定义。

答案 1 :(得分:3)

对规范有更好了解的人可以证实这一点,但我相信,Wrap<T>是一种比简单T更具体的类型,在所有平台编译器上,调用2将始终解析为“选择2”。

答案 2 :(得分: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 :(得分:1)

可能会使问题更加严重的一件事是,专门化模板类和模板函数的规则差异很大。这样就可以在不存在重载类的情况下重载模板函数。因为我对这个话题不那么坚定,所以我会链接到能够更深入地解释它的人:

Herb Sutter: "Why Not Specialize Function Templates?"