13

Let's have this code:

Test1 t1;
Test2 t2;
t1 = t2;

I believe there are three (or more?) ways how to implement t1 = t2

  • to overload assign operator in Test1
  • to overload type cast operator in Test2
  • to create Test1(const Test2&) conversion constructor

According to my GCC testing, this is the priority of what is used:

  1. assign operator
  2. conversion constructor and type cast operator (ambiguous)
  3. const conversion constructor and const type cast operator (ambiguous)

Please help me understand why this priority.

I use this code for testing (uncomment some lines to try out)

struct Test2;
struct Test1 {
  Test1() { }
  Test1(const Test2& t) { puts("const constructor wins"); }
//  Test1(Test2& t) { puts("constructor wins"); }
//  Test1& operator=(Test2& t) { puts("assign wins"); }
};

struct Test2 {
  Test2() { }
//  operator Test1() const { puts("const cast wins"); return Test1(); }
//  operator Test1() { puts("cast wins"); return Test1(); }
};


int main() {
  Test1 t1;
  Test2 t2;
  t1 = t2;
  return 0;
}
Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
  • `Test1::Test1(const Test2&)` is not a "copy constructor", it is a "converting constructor". – aschepler Sep 09 '12 at 01:02
  • This post explains exactly why conversion operator is of higher precedence: http://stackoverflow.com/questions/1384007/conversion-constructor-vs-conversion-operator-precedence – Baiyan Huang Sep 09 '12 at 01:20

2 Answers2

15

The statement t1 = t2; is equivalent to:

t1.operator=(t2);

Now the usual rules of overload resolution apply. If there's a direct match, that's the chosen one. If not, then implicit conversions are considered for use with the (automatically generated, "implicitly defined") copy-assignment operator.

There are two possible implicit, user-defined conversions. All user-defined conversions count equal, and if both are defined, the overload is ambiguous:

  • Convert t2 to a Test1 via the Test1::Test1(Test2 const &) conversion constructor.

  • Convert t2 to a Test1 via the Test2::operator Test1() const cast operator.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • In @Luchian's second ideone example, the conversion function wins because it binds a `Test2&` to `t2`, not a `const Test2&`. I thought http://ideone.com/U38vK was supposed to be ambiguous too, but it seems g++ prefers the constructor. – aschepler Sep 09 '12 at 01:13
  • 2
    Aha. g++ DOES call them ambiguous if you ask for `-pedantic`. Naughty default g++. – aschepler Sep 09 '12 at 01:34
  • @KerrekSB: If the cast operator is not constant, it beats the conversion constructor and there is no ambiguity. http://liveworkspace.org/code/7795254ae49b4d6350f0ede57615e4c6 – Jan Turoň Sep 09 '12 at 01:37
  • @JanTuroň: Yes, I know. And if you make the constructor non-const as well, you can get the ambiguity back. – Kerrek SB Sep 09 '12 at 01:49
  • @JanTuroň: The exact same reason. – Kerrek SB Sep 09 '12 at 01:53
  • @KerrekSB: OK, why the non-constant version of operator/constructor wins over the constant version of constructor/operator? – Jan Turoň Sep 09 '12 at 01:57
  • @JanTuroň: Because `t2` is non-const. You can also try things like `t1 = static_cast(t2);` and compare. – Kerrek SB Sep 09 '12 at 01:58
  • @KerrekSB: OK, now it is clear. Thank you, it was a long struggle. – Jan Turoň Sep 09 '12 at 02:00
  • @JanTuroň: Awesome. Overload resolution is a very complex part of C++, so it's important to understand it right. – Kerrek SB Sep 09 '12 at 02:01
  • @KerrekSB : since when does it make any sense for a constructor to be const or non-const ? Constructors cannot be cv-qualified – Jean-Bernard Jansen Feb 28 '15 at 17:29
0

when I use following code than priority is given first to the constructor rather than cast operator

 #include<iostream>
 using namespace std;
 class C1;
 class C2
 {
      int x;
 public:
     operator C2()
     {
       C2 temp;
       cout<<"operator function called"<<endl;
       return temp;
    }
 };
class C1
{
   int x;
public:
   C1():x(10){}
   C1(C2)
  {
    cout<<"constructor called"<<endl;
  }
};
 int main()
{
  C1 obj1;
  C2 obj2;
  obj1=obj2;
}

Output Constructor called

Pritul Dave
  • 189
  • 1
  • 11