2010-04-25 62 views
5

關於下面的代碼,編譯器如何選擇調用哪個模板函數? 如果const T &函數被省略,則始終調用T &函數。 如果省略T &功能,則始終調用const T &函數。 如果兩者都包含在內,則結果如下。編譯如何選擇調用哪個模板函數?

#include <iostream> 
#include <typeinfo> 

template <typename T> 
void function(const T &t) 
{ 
    std::cout << "function<" << typeid(T).name() << ">(const T&) called with t = " << t << std::endl; 
} 

template <typename T> 
void function(T &t) 
{ 
    std::cout << "function<" << typeid(T).name() << ">(T&) called with t = " << t << std::endl; 
} 

int main() 
{ 
    int i1 = 57; 
    const int i2 = -6; 

    int *pi1 = &i1; 
    int *const pi3 = &i1; 
    const int *pi2 = &i2; 
    const int *const pi4 = &i2; 

    function(pi1); ///just a normal pointer -> T& 
    function(pi2); ///cannot change what we point to -> T& 
    function(pi3); ///cannot change where we point -> const T& 
    function(pi4); ///cannot change everything -> const T& 

    return 0; 
} 

/* g++ output: 
function<Pi>(T&) called with t = 0x22cd24 
function<PKi>(T&) called with t = 0x22cd20 
function<Pi>(const T&) called with t = 0x22cd24 
function<PKi>(const T&) called with t = 0x22cd20 
*/ 

/* bcc32 output: 
function<int *>(T&) called with t = 0012FF50 
function<const int *>(T&) called with t = 0012FF4C 
function<int *>(const T&) called with t = 0012FF50 
function<const int *>(const T&) called with t = 0012FF4C 
*/ 

/* cl output: 
function<int *>(T&) called with t = 0012FF34 
function<int const *>(T&) called with t = 0012FF28 
function<int *>(const T&) called with t = 0012FF34 
function<int const *>(const T&) called with t = 0012FF28 
*/ 
+0

一個小技巧,當你碰巧使用G ++是。 '__PRETTY_FUNCTION__'提供了一個格式良好的字符串來描述你的函數,包括模板參數類型[「int *」而不是「Pi」]。在學習模板如何工作時,我發現這是非常寶貴的,因爲在g ++下'typeid(T).name()'的默認行爲是相當神祕的。我相信'__FUNCSIG__'在VS下提供了類似的功能,但我無法訪問它進行驗證。 – 2010-04-25 17:16:43

回答

3

Here是編譯器經歷的過程的簡要概述。它並不包含所有內容,但它讓你開始。

在這種情況下,做出的決定與非模板化功能相同。給定void f(int&)void f(const int&),第一個將被選擇用於常規整數,第二個用於const整數。參數只是簡單地匹配輸入:如果你提供了一個你可以修改的變量,它會調用一個函數來修改它們,如果你提供了一個你不能修改的變量,它會調用一個不能修改它的函數。

在您的示例代碼中,pi2被聲明爲const int *,它是一個非常數指針。因此,在您的功能中,您可以更改t,但不能更改*t。相比之下,pi3是一個指向非常數數據的常量指針。所以你可以改變*t而不是t

如果你改變了你略微代碼:

function(*pi1); 
function(*p12); 
function(*pi3); 
function(*pi4); 

在這種情況下,第一和第三既能解決的T&版本,因爲*pi1*pi3都是int&類型的,因此可以修改。 *pi2*pi4都是const int&,所以他們解析爲const T&過載。

0

這是關於變量本身是否爲常量: 第一個並不是恆定的。 第二個指向的東西是不變的,但我們可以改變指向的位置,第三個和第四個都有一個常量指針,這意味着變量本身是const的,我們不能改變它指向的任何地方。

typedef const int Cint; 
Cint * int1; 

顯然是指向常量int的指針。

typedef int * Pint 
const Pint int2 

明顯常量指針到非恆定INT