简体   繁体   中英

Call to template base constructor is ambiguous

The following code

template<class T>
struct Bar
{
  Bar(T& myT){}
  Bar(const Bar&) = delete;
};

template<class T>
struct Foo: public T,
            public Bar<T>
{
    Foo(): Bar<T>(*this){}
};

class Baz{};

int main()
{
    Foo<Baz> myFoo;
    return 0;
}

Gives me this error:

error: call to constructor of 'Bar<Baz>' is ambiguous

How can I fix this?

(Seems simple, I'm sure there's a duplicate somewhere, but I couldn't find it... all questions I found with "ambiguous constructor" stuff had to do with overloaded constructors, and this seems different to me.)

You have two constructors in Bar<Baz> :

Bar(Baz& );
Bar(const Bar& );

The fact that the second is deleted doesn't matter for the purposes of overload resolution. You are trying to construct it from a Foo<Baz>& ... which is both a Baz and a Bar<Baz> , so both overloads apply - and the compiler can't prefer one over the other, so gives you the ambiguous error. Here's a simpler example with no templates that demonstrates the same issue:

struct A { };
struct B { };

struct C : A, B { };

void foo(A& ) { }
void foo(B& ) { }

int main() {
    C c;
    foo(c); //  error: call of overloaded ‘foo(C&)’ is ambiguous
}

To break the ambiguity, could just explicitly tell the compiler which overload to use with casting:

Foo(): Bar<T>(static_cast<T&>(*this)) {} // will call Bar(Baz&)

Deleted constructors participate in overload resolution. This is in order to ensure that the compilation really fails if a program attempts to use a deleted constructor. See this answer for more details.

The relevant section in the C++11 standard is 8.4.3/2:

A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.

[ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. —end note ]

You can solve your problem by making the constructor call unambiguous:

template<class T>
struct Foo: public T,
            public Bar<T>
{
    Foo(): Bar<T>(static_cast<T &>(*this)){}
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM