В 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!!
но было бы более хорошо, если бы я не имел к...
Я думал, что механизм поиска аргументов шаблона будет достаточно умен, чтобы определить правильный базовый производитель.
Это не связано с шаблонами, это происходит из-за использования нескольких базовых классов - поиск имени уже неоднозначен, и только после этого происходит разрешение перегрузки.
Упрощенный пример будет следующим:
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;
};
Вы можете просто использовать явную квалификацию в вызове функции. Вместо:
producer.SetConsumer(&consumer);
попробуйте:
producer.Producer<AppleConsumer>::SetConsumer(&consumer);