2012-04-25 66 views
5

我想不通,爲什麼下面的代碼編譯罰款:C++函數模板instantiaion與隱含參數

#include <iostream>                 

void bar(int x) {                 
    std::cout << "int " << x << std::endl;            
}                     

void bar(double x) {                 
    std::cout << "double " << x << std::endl;           
}                     

template <typename A, typename B> // Note the order of A and B.            
void foo(B x) {                  
    bar((A)x);                   
}                     

int main() {                   
    int x = 1;                   
    double y = 2;                  

    foo<int>(x);  // Compiles OK.                
    foo<double>(y);  // Compiles OK.            

    return 0;                   
} 

但是如果我切換的AB如下的順序,那麼它將無法編譯:

#include <iostream>                 

void bar(int x) {                 
    std::cout << "int " << x << std::endl;            
}                     

void bar(double x) {                 
    std::cout << "double " << x << std::endl;           
}                     

template <typename B, typename A> // Order of A and B are switched. 
void foo(B x) {                  
    bar((A)x);                   
}                     

int main() {                   
    int x = 1;                   
    double y = 2;                  

    foo<int>(x);  // error: no matching function for call to ‘foo(int&)’ 
    foo<double>(y);  // error: no matching function for call to ‘foo(double&)’                

    return 0;                   
}  

編輯:特別解釋是受歡迎的,但會更好,如果有人能指出確切的規範。說。謝謝!

+1

編譯器可以從傳遞給foo構造函數的參數(類型B)推斷出第一個示例中的B的類型。在第二個示例中,不能進行這種推理,因爲提供的模板參數是B,構造函數參數也是如此。 A的類型沒有任何證據。 – Stabledog 2012-04-25 20:56:27

回答

7

在第一個,編譯器知道Aint,因爲你明確告訴它,以便與foo<int>,並且它知道Bint,因爲你通過它的參數。因此,AB都是已知的或可以推導出的(可以說:A提供的B暗示的)。

然而,在第二個,因爲B至上和A沒有出現在參數列表中,編譯器不能告訴A是,給你一個錯誤。您明確告訴它Bfoo<int>是什麼,然後您傳遞的參數也是B,在調用時,它是一個int,它與您之前明確定義的B一致,但沒有提及A,隱含地或者明確地說,所以編譯器必須停止並出錯。

你不需要這個標準,這只是常識。 A究竟會在第二個?

儘管感謝您提出這個問題,因爲我沒有意識到您可以顯式指定某些參數,並在此之前隱式指定參數列表中的其他參數。

+0

所以,這成爲了什麼規範的問題。說如何確定'A'和'B'。由於輸入參數先編譯器可能已經確定了'B',然後從'foo '中找出'A'。然後,即使在第二種情況下,也確定兩個模板參數。 – kirakun 2012-04-25 20:56:39

+1

@Kirakun不是真的。只有在'<>'中指定了一個類型,或''>'中沒有指定的所有類型都在參數列表中,才能確定'A'和'B',因此編譯器可以推導出鍵入來電。在第二個中,'A'既沒有在'<>中顯式指定也沒有在參數列表中,所以它不能被知道。 – 2012-04-25 20:58:03

+1

@Kirakun僅僅是因爲你把一個放在參數列表中並不意味着當你開始在'<>'之間放置它時它會被跳過。它們仍然按照它們在列表'template '中的順序排列,因此無論函數採用哪個參數,都是先B',然後是A'。 – 2012-04-25 20:58:50