0

I think the question is pretty simple and it can be shrunk in few words such "which operator does the compiler overload automatically?" I've got an idea about what is going on but I'm currently missing some details able to explain me why it's working as it's.

Unfortunately I did not find anything of useful into my Stroustrup's C++ reference and I'm pretty sure that somebody of you can help me figuring out what's happening. Let's open the discussion: here's a little snapshot something similar to the code I was looking at:

class MyPair : public pair<string,string>
{
    public:
    MyPair()
    {
        pair<string,string>();
    }
};

So far nothing of strange, as widely discussed in the thread What are all the member-functions created by compiler for a class? Does that happen all the time? the compiler will automatically generate a default version of copy constructor a copy assignment operator and a destructor but not a default constructor just because I redefined my own. Thanks to the compiler I'll be able to assign a new object at the creation time using the default copy constructor and to use the assignment operator just after the creation of an object, as showed here:

//default copy constructor
MyPair mypair1 = mypair;
MyPair mypair2;
//default assignment operator
mypair2 = mypair1

Until now, everything works as designed. Imagine now that I would like, for some unknown reason, to assign a string object to MyPair object, like it follows:

int main()
{
    pair<string,string> aPair;
    MyPair mypair;
    string mystring("test");
    //ERROR
    mypair = mystring;
    return 0;
}

Before I tested out this line of code, I was expecting that the compiler would have complained about (because I didn't provide to it any explicit overload of the operator=, so by itself is not able to assign a string to the created object), and indeed it returned me a quite self-explicative error, like:

test.cpp:36:13: error: no match for ‘operator=’ in ‘mypair = mystring’
test.cpp:36:13: note: candidate is:
test.cpp:7:7: note: MyPair& MyPair::operator=(const MyPair&)

Now, imagine to complete the MyPair class by adding the following method:

MyPair(const string& astring)
{
    pair<string,string>(astring,string());
}

Suddenly, the code starts compiling, without giving anymore any kind of error. To my eyes it seems that the above method provided to the compiler some kind of cleverness; it started generating the missing MyPair& MyPair::operator=(const string &s).

I have to admit that it sounds really brilliant, but I cannot understand exactly why it happens. Would it mean that for each additional constructor I put in place into MyPair the coplier will generate an additional overloaded operator= that makes my class being copy assignable to the specified reference just because of that?

Community
  • 1
  • 1
tonyqui
  • 34
  • 3
  • It first converts to MyPair, then assigns. Two calls. – Marc Glisse Feb 08 '14 at 10:57
  • "it started generating the missing MyPair& MyPair::operator=(const MyPair&)". You mean the missing `operator=(const string &s)`? No, this one still misses like the others also point out. There is only created a *temporary* MyPair, what is a waste of time/space. So you should implement the missing `operator=(const string &s)`. – mb84 Feb 08 '14 at 11:12
  • Yes, right, sorry for the typo, I meant operator=(const string &s) – tonyqui Feb 08 '14 at 12:13
  • Nevermind your question. Your very first snippet of code betrays a serious misunderstanding. Inside `{}` the code `pair()` does **not** construct your parent. And note that `pair` was not designed to be inherited from, so your design is also fundamentally questionable. – Yakk - Adam Nevraumont Feb 08 '14 at 12:47
  • Yakk thanks for remark, I know that the design is quite questionable... To be more precise I'm questioning alot about it, that's why I'm here for the question. The purpose of my exaple was more to have a practical example to start discussing about the syntactical aspects of the language. Anyway, many thanks to share your idea about it, I'll definitely take it in mind whenever I'll have to work at it. – tonyqui Feb 08 '14 at 16:06

2 Answers2

1

MyPair(const string& astring) is an implicit conversion constructor. Your string is first used to create a new MyPair which is then assigned to your object. You can disallow this behavior by marking it explicit:

explicit MyPair(const string& astring)

This prevents implicit conversion, so

mypair = mystring; 

is illegal, while

mypair = MyPair(mystring);

still works.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • Many thanks, I was missing the definition of **conversion constructors**. A kind of clear definition for them is here [stackoverflow page](http://stackoverflow.com/questions/15077466/what-is-a-converting-constructor-in-c-what-is-it-for): " A **constructor** declared **without the function-specifier explicit** that can be called with a **single parameter** specifies a _conversion from the type of its first parameter to the type of its class_. Such a constructor is called a converting constructor". Any clue about how it's implemented by the compiler itself? Does it just overload operator=? – tonyqui Feb 08 '14 at 12:30
  • @user3286843 the compiler doesn't implement it, you do. The `MyPair(const string& astring)` is the conversion constructor. – Luchian Grigore Feb 08 '14 at 12:38
1

Just to inform you that your way of initializing the base class member is not right.

MyPair()
{
    pair<string,string>();
}

should instead be:

MyPair() : pair<string, string>()
{
}

and

MyPair(const string& astring)
{
    pair<string,string>(astring,string());
}

should instead be:

MyPair(const string& astring) : pair<string, string>(astring, string())
{
}

As for why assignment is working, a temporary of MyPair is created using the constructor and is used as the argument to the assignment operator.

neverhoodboy
  • 1,040
  • 7
  • 13