What the =?

February 10, 2009
#include <iostream>
using namespace std;
 
struct Foo {
    Foo() {
        cout<<"Default constructor."<<endl;
    }
    Foo(Foo const&) {
        cout<<"Copy constructor."<<endl;
    }
    Foo(int) {
        cout<<"Conversion constructor."<<endl;
    }
    Foo& operator = (int) {
        cout<<"Assignment operator."<<endl;
        return *this;
    }
};
 
int main() {
    Foo a(1);
    Foo b = 1;
    Foo c = Foo(1);
    return 0;
}

Do you know what this program will output?

I have the impression that most C++ programmers will tell you that the first will invoke the conversion constructor, but will be split on whether the second and third forms call the conversion constructor and the assignment operator, or the conversion constructor and the copy constructor.  This means that I have the impression that most C++ programmers don’t know what these statements really mean to the C++ compiler.

The Form Type t = expr;

The expression Foo b = 1; is an alternate way of saying Foo b(1);.  Both are considered forms of direct initialization by the C++ language specification, so no assignment or copy constructor is invoked.  In a statement which declares and initializes a variable, the = is not a true assignment operator, but an indication to the compiler of how to initialize the value.

The Form Type t = Type(expr);

In C++, constructors don’t really have names.  The syntax

Foo(1);

is not really considered a function call (where the function happens to be a constructor), it is actually considered to be an explicit type conversion from 1 to Foo.  This is commonly called a function-style cast and is closer to int(5.3f) than a function call. The only difference is that multiple values can be used in a function-style cast for user-defined types.

If we combine these facts, we can conclude that the statement Foo c = Foo(1); only invokes the conversion constructor as well.  The = indicates initialization and the Foo(1) only casts the type; therefore, again, only the conversion constructor is called.

Other Conversions

Since constructors are invoked for conversions, there are other forms which are simply constructor invocations:

(Foo) 1;
static_cast<Foo>(1);

Both of these could replace Foo(1) above without changing the meaning of the statement.

Tags: C++ fixme