Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Ambiguous base class" error in template context

I have this function template:

template <class TemplateArgument, template<class> class TemplateType>
TemplateArgument f(const TemplateType<TemplateArgument>& arg)
{
    return TemplateArgument();
}

When used like this, it fails to compile:

struct A {};
template <typename T> struct S {};
template <typename T> struct B : public S<T> {};

struct C : public B<A> {};

int main()
{
    f(C());
    return 0;
}

And the error message is:

<source>: In function 'int main()':

<source>:15:10: error: no matching function for call to 'f(C)'

     f(C());

          ^

<source>:2:18: note: candidate: template<class TemplateArgument, template<class> class TemplateType> TemplateArgument f(const TemplateType<TemplateArgument>&)

 TemplateArgument f(const TemplateType<TemplateArgument>& arg)

                  ^

<source>:2:18: note:   template argument deduction/substitution failed:

<source>:15:10: note:   'const TemplateType<TemplateArgument>' is an ambiguous base class of 'C'

     f(C());

          ^

Happens with GCC (any version) and clang (any version). Does not happen with MSVC. Live demo: https://godbolt.org/g/eWxeHJ

Why does this error occur? I fail to see any ambiguity, the "ambiguous base class" error usually occurs in multiple inheritance situations, does it not? How can I make my code compile (deduce template arguments correctly)?

Note that I cannot edit the A, B, C, S classes and their relation to each other, I can only edit my function f() to accept these classes properly.

like image 503
Violet Giraffe Avatar asked Jun 24 '18 10:06

Violet Giraffe


1 Answers

The compiler is not sure whether to deduce args type as B<A> or S<A>. I'm not sure about this specific case but MSVC is known to violate the standard especially when it comes to templates.

As for your function, you need to resolve this ambiguity yourself by explicitly casting to the appropriate base:

f((const B<A> &)C());

or by specifying template parameters explicitly:

f<A, B>(C());

Generally whenever there is any ambiguity in the language it is never automatically resolved by the compiler because it would just be a speculation about what exactly did user intend, which might be right in some cases and completely wrong in others.

like image 63
r3mus n0x Avatar answered Nov 05 '22 21:11

r3mus n0x