1

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.)

Alex Whitt
  • 13
  • 3

2 Answers2

0

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&)
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Interesting, I didn't realize the compiler wouldn't care about the deletion... is there a way to get around this and still accomplish what I want? (keeping the structure as I have it?) – Alex Whitt Oct 26 '14 at 02:59
  • @AlexWhitt You could explicitly cast it... call the constructor with `static_cast(*this)`. – Barry Oct 26 '14 at 03:00
  • Ahh I guess that's what I'll have to do, thank you! (I think @jogojapan barely beat you to the punch though!) – Alex Whitt Oct 26 '14 at 03:09
0

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)){}
};
Community
  • 1
  • 1
jogojapan
  • 68,383
  • 11
  • 101
  • 131
  • 1
    Ahh gotcha, thank you! I guess I've always shied away from explicit casting like that so I didn't even consider it XP but that's what I'll have to do! – Alex Whitt Oct 26 '14 at 03:10