2011-08-11 42 views
1

如果我编译器(gcc 4.6.0),然后运行该代码:全局函数模板重载和const参数

#include <iostream> 

template <typename T> void F(/* const */ T& value) { 
    std::cout << "T & " << value << std::endl; 
} 

template <typename T> void F(/* const */ T* value) { 
    std::cout << "T * " << value << std::endl; 
    F(*value); 
} 

int main(int argc, char* argv[]) { 
    float f = 123.456; 
    float* pf = &f; 

    F(pf); 

    return 0; 
} 

我得到以下输出:

T * 0x7fff7b2652c4 
T & 123.456 

如果我去掉const的关键字我得到以下输出:

T & 0x7fff3162c68c 

我可以改变float* pf = &f;const float* pf = &f;再次获得原始输出,这不是问题。

我想知道的是,为什么在使用const修饰符进行编译时,重载解析认为const T& valueconst T* value更适合非const float*

回答

3

在重载解析,无需转换的重载需要打一些转换过载,即使这些转换是微不足道的。引述C++ 03标准,[over.match.best](§13.3.3/ 1):

定义ICS F)如下:

  • 如果F是一个静态成员函数,ICS (F)被限定为使得ICS (F)既不大于ICS (G),用于任何功能G更好也不差,和对称, ICS (G)既不大于ICS (F)更好也不差;否则,
  • 设ICS F)表示的是,在列表中的个参数转换为可行函数F个参数的类型的隐式转换序列。 13.3.3.1定义了隐式转换序列,13.3.3.2定义了一个隐式转换序列是一个比另一个更好的转换序列或更糟的转换序列。

根据这些定义,一个可行的功能F1被定义为比另一种可行的功能F2一个更好功能,如果对所有的参数,ICS F1)不大于一个糟糕的转换序列ICS F2),然后

  • 对于一些参数Ĵ,ICS ĴF1)比ICS Ĵ更好的转换序列(F2),或者,如果不是,
  • F1是一个非模板函数和F2是一个函数模板特,或者,如果不是,
  • F1F2是功能模板特,而对于F1函数模板是根据在14.5.5.2描述的部分排序规则比模板F2更专门的,或者,如果不是,
  • 的上下文是通过用户定义的转换进行初始化(请参见8.5,13.3.1.5和1 3.3.1.6),并且从返回类型F1到目标类型(即,正在初始化的实体的类型)的标准转换序列是比从返回类型F2到目标类型的标准转换序列更好的转换序列。

const是目前,为了调用过载取的基准,无需进行转换 - T被推断为float*和参数是float* const&。但是,为了通过指针调用过载,float将需要转换为float const,以使所述超载可行。因此,参考超载会获胜。

当然,请注意,如果pf更改为float const*,则行为将回到您的预期方式,因为采用指针的重载不再需要转换。