In Visual Studio 2008, the compiler cannot resolve the call to SetCustomer
in _tmain
below and make it unambiguous:
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;
}
This is the compilation error:
// error C2385: ambiguous access of 'SetConsumer'
// could be the 'SetConsumer' in base 'Producer<AppleConsumer>'
// or could be the 'SetConsumer' in base 'Producer<MeatConsumer>'
I thought the template argument lookup mechanism would be smart enough to deduce the correct base Producer
. Why isn't it?
I could get around this by changing Producer
to
template <typename TConsumer>
struct Producer
{
template <typename TConsumer2>
void SetConsumer(TConsumer2* consumer) { consumer_ = consumer; }
TConsumer* consumer_;
};
and call SetConsumer
as
producer.SetConsumer<AppleConsumer>(&consumer); // Unambiguous call!!
but it would be nicer if I didn't have to...
I thought the template argument lookup mechanism would be smart enough to deduce the correct base Producer.
This hasn't to do with templates, it comes from using multiple base classes - the name lookup is already ambiguous and overload resolution only takes place after that.
A simplified example would be the following:
struct A { void f() {} };
struct B { void f(int) {} };
struct C : A, B {};
C c;
c.f(1); // ambiguous
Workarounds are explicitly qualifying the call or to introduce the functions into the derived classes scope:
struct ShillyShallyProducer : public Producer<AppleConsumer>,
public Producer<MeatConsumer>
{
using Producer<AppleConsumer>::SetConsumer;
using Producer<MeatConsumer >::SetConsumer;
};
You can just use explicit qualification in your function call. Instead of:
producer.SetConsumer(&consumer);
try:
producer.Producer<AppleConsumer>::SetConsumer(&consumer);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With