Arthur Z
Arthur Z

Reputation: 3

Call to overloaded constructor gives ambiguis error C++

I am currently working on a small project, where I manipulate an enumeration :

enum ThreeVal_t {T='T',F='F',U='U'};

And I want to create Atom. Defined as follows :

class Atom : 
{
private:
    std :: string name;
    ThreeVal_t val;
    static int id;

public:
    //constructors
    Atom();
    Atom(const Atom &at);
    Atom(const ThreeVal_t at);
    Atom(const ThreeVal_t &at);
    //Destructor
    ~Atom();
};

Operators are defined as follows

Atom::Atom() : name("a_" + std::to_string(id)), val(U)
{
    id++;
}
Atom::Atom(const Atom &at) : name("a_" + std::to_string(id)), val(at.val)
{
    id++;
}
Atom::Atom(const ThreeVal_t at) : name("a_" + std::to_string(id)), val(at)
{
    id++;
}
Atom::Atom(const ThreeVal_t &at) : name("a_" + std::to_string(id)), val(at)
{
    id++;
}

My problem is that when I call Atom a(U) i get the following error from my clang compiler :

error: call to constructor of 'Atom' is ambiguous
  Atom a(U);
       ^ ~
note: candidate constructor
        Atom(const ThreeVal_t at);
        ^
note: candidate constructor
        Atom(const ThreeVal_t &at);
        ^
note: candidate constructor
        Atom(const Atom &at);


But I thought that since the declaration and definition were different, it would work. Do you know why it's ambiguous?

Upvotes: 0

Views: 39

Answers (1)

Richard Hodges
Richard Hodges

Reputation: 69854

The problem is that in the expression:

Atom A(U)

U can equally correctly be interpreted as a reference to U or a copy of U. It therefore binds to both constructor signatures. This is the source of the ambiguity.

In general you'll want to choose one of the signatures. If the intent is to take a copy (or move a temporary into the object) then pass by value. If the intent is to work with an immutable reference to an existing object that will persist after the call to the constructor, pass by const reference.

class Atom
{
  // ...
public:
    // pass by value
    Atom(ThreeVal_t at);
  // ...
};

class Atom
{
  // ...
public:
    // pass by const reference
    Atom(ThreeVal_t const & at);
  // ...
};


Upvotes: 1

Related Questions