Home > Back-end >  Resolve ambiguity in assignment constructor c
Resolve ambiguity in assignment constructor c

Time:11-21

Description

I have code that is ambiguous when a certain constructor is present. But, when I comment said constructor out, then the compiler complains that a necessary constructor is missing.

Minimum Working Example

struct X;

struct E{
    E(const double& r){ /* important protocol stuff */ }
    E(const X&);
};

struct X{
    X(){ /* important init stuff */ }
    ~X(){ /* important delete stuff */ }
    //X(const double& r){ *this=E(r); }  // POSITION 1
    X(const X& x){ /* important init stuff */ *this=x; }
    X(const E& e){ /* important init stuff */ *this=e; }
    const X& operator=(const X& x){ return *this=E(x); }
    const X& operator=(const E& e){ /* important stuff */ return *this; }
};

E::E(const X& x){ /* important protocol stuff */ }

E operator (const E& x, const E& y){ /* important protocol stuff */ return E(1); }
E operator*(const E& x, const E& y){ /* important protocol stuff */ return E(2); }

int main(){
    X x,y;
    x = 3.0;
    X u = 4.0;  // POSITION 2
    y = x   u * 5.0;
    X z = 6.0   7.0 * y;
}

With position 1 commented out, position 2 throws an error.

With position 1 included, there is an ambiguity error.

Basically, I want to remove position 1 and with that double->X be cast via double->E->X.

Questions

  1. What is the name of the problem?
  2. How do I fix it?

Things I tried:

  • explicit keywords in front of various constructors. For E, this results in errors after position 2. For X, this results in the same error as with position 1 commented out.
  • removing constructors/operators from the definitions from X,E. This however is no solution, because I need to be able to include some important stuff.
  • trying different compilers (g 8.3.0 and 9.2.0, clang 12.0.0). This did not change the issue.

CodePudding user response:

The ambiguity occurs because (in the x = 3.0; line) the compiler can't decide which of the two assignment operators to use: the one with the X& argument or the one with the E&, as both parameter types are convertible from the given double (because both E and X have constructors that take a const double& parameter).

You can resolve this error by providing a third assignment operator, which takes a const double& argument, like so:

struct X {
    X() { /* important init stuff */ }
    ~X() { /* important delete stuff */ }
    X(const double& r){ *this=E(r); }  // Now uncommented (required)
    X(const X& x) { /* important init stuff */ *this = x; }
    X(const E& e) { /* important init stuff */ *this = e; }
    const X& operator=(const double& x) { return *this = E(x); } // Add this!
    const X& operator=(const X& x) { return *this = E(x); }
    const X& operator=(const E& e) { /* important stuff */ return *this; }
};
  • Related