2010-04-26 98 views
8

在Visual Studio 2008中,編譯器無法解析調用SetCustomer以下_tmain,使其明確:曖昧訪問基類模板成員函數

template <typename TConsumer> 
struct Producer 
{ 
    void SetConsumer(TConsumer* consumer) { consumer_ = consumer; } 

    TConsumer* consumer_; 
}; 

struct AppleConsumer 
{ 
}; 

struct MeatConsumer 
{ 
}; 

struct ShillyShallyProducer : public Producer<AppleConsumer>, 
           public Producer<MeatConsumer> 
{ 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ShillyShallyProducer producer; 
    AppleConsumer consumer; 
    producer.SetConsumer(&consumer); // <--- Ambiguous call!! 

    return 0; 
} 

這是編譯錯誤:

// error C2385: ambiguous access of 'SetConsumer' 
// could be the 'SetConsumer' in base 'Producer<AppleConsumer>' 
// or could be the 'SetConsumer' in base 'Producer<MeatConsumer>' 

我認爲模板參數查找機制足夠聰明,可以推導出正確的基地Producer。爲什麼不是?

我能解決這個問題,通過改變Producer

template <typename TConsumer> 
struct Producer 
{ 
    template <typename TConsumer2> 
    void SetConsumer(TConsumer2* consumer) { consumer_ = consumer; } 

    TConsumer* consumer_; 
}; 

,並呼籲SetConsumer作爲

producer.SetConsumer<AppleConsumer>(&consumer); // Unambiguous call!! 

,但如果我沒得還要好......

+0

我只是想指出在你提出的解決方法中,你不需要調用'SetConsumer (&consumer)','SetConsumer(&consumer)'就足夠了(並且正確地推導出模板參數)。 – sbk 2010-04-26 12:51:27

+0

@sbk:不,它不會。我在發佈之前嘗試過,現在再次確定。仍然含糊不清。 – 2010-04-26 13:19:55

回答

12

I thought the template argument lookup mechanism would be smart enough to deduce the correct base Producer.

這已經不是用模板做的,它來自使用多個基類 - 這個名字查找已經含糊不清,重載決議只需要之後的地方。

一個簡化的例子是下面的:

struct A { void f() {} }; 
struct B { void f(int) {} }; 
struct C : A, B {}; 

C c; 
c.f(1); // ambiguous 

變通辦法被明確出線呼叫或來介紹這些功能到派生類範圍:

struct ShillyShallyProducer : public Producer<AppleConsumer>, 
           public Producer<MeatConsumer> 
{ 
    using Producer<AppleConsumer>::SetConsumer; 
    using Producer<MeatConsumer >::SetConsumer; 
}; 
+0

@gf:「將函數引入派生類作用域」 - 這是一個很好的解決方案,因爲我不想每次添加新的產品時都更改生產者客戶端的調用站點。可愛 - 謝謝! – 2010-04-26 12:22:36

2

您可以在函數調用中使用顯式限定。相反的:

producer.SetConsumer(&consumer); 

嘗試:

producer.Producer<AppleConsumer>::SetConsumer(&consumer);