0

I was trying a move constructor example as shown below:

#include <iostream>
#include <string.h>

using namespace std;

class Class1
{   
    string name;

public:

    //Parameterized ctor
    Class1(string nm): name(nm)
    {
        cout <<"\nClass1 Parameterized Constructor" << endl;
    }

    //move ctor
    Class1(string&& other): name(std::move(other))
    {
        cout <<"\nClass1 Move Constructor" << endl;
    }

    
};


class Class2
{

    Class1 class1_obj;

public:

    //Parameterized ctor
    Class2(Class1 param): class1_obj(param)
    {
        cout <<"\nClass2 Parameterized Constructor" << endl;
    }

    //move ctor
    Class2(Class1&& param): class1_obj(std::move(param))
    {
        cout <<"\nClass2 Move Constructor" << endl;
    }
    
};


int main()
{
    string obj7("Suraj");
    Class1 obj6(obj7);
    Class2 obj5(move(obj6));

    return 0;
}

Compiler is generating following error:

error: call of overloaded 'Class2(std::remove_reference<Class1&>::type)' is ambiguous Class2 obj5(move(obj6));

I changed the Class2 parameterized ctor by adding a reference to the parameter in the definition as:

Class2(Class1& param): class1_obj(param)
{
    cout <<"\nClass2 Parameterized Constructor" << endl;
}

What is the reason for this error? Is the solution correct, and if yes, what should be done to declare the same ctor without a reference?

surajj4837
  • 49
  • 1
  • 10
  • why did you write those two constructors? Whats the aim? I hope you are not just randomly adding `&` somewhere – 463035818_is_not_an_ai Feb 11 '23 at 09:52
  • I m just trying to learn the move semantics. First I created the parameterized ctor and then added the move ctor, just step-by-step code development. – surajj4837 Feb 11 '23 at 09:56
  • fwiw, "parametrized constructor" is a not very useful term, constructors with parameters are not special. Constructors that can be called without arguments are special, they are default constructors, `Class2(int x = 0) {}` is a default constructor. – 463035818_is_not_an_ai Feb 11 '23 at 09:56
  • 1
    @surajj4837 See this [dupe](https://stackoverflow.com/a/17961890/12002570) – Jason Feb 11 '23 at 09:57

1 Answers1

4

It is not possible to overload on by-value vs by-reference. That is always ambiguous. That's simply how the language was designed. It would be hard to make a useful general choice between the two.

If you want to handle rvalues specifically, then let the first overload of the constructor take const Class1& instead of Class1.

However, in most cases just a single by-value constructor is good enough:

Class2(Class1 param): class1_obj(std::move(param))
{ /*...*/ }

This will also use the move constructor instead of the copy constructor where possible. The only negative is that is might use one extra move construction in the end, which is normally not a problem.

(The same issue applies to Class1's constructors by the way. You just happened to test it only with lvalue arguments, where the rvalue reference overload is non-viable. If you try it with a rvalue, then it will cause the same problem.)

user17732522
  • 53,019
  • 2
  • 56
  • 105