Take a look at this innocent looking piece of code in C++. There are no templates, no virtual functions or inheritance, but the creators of this beautiful language hid a gift right in front of us.

struct A { A (int i) {} }; struct B { B (A a) {} }; int main () { int i = 1; B b(A(i)); // (1) return 0; }

Question: What is the type of variable b? It is not the one you would expect at first glance.

Analysis

Well, the type of variable b is definitely not B. Otherwise, why would I write this article at all? I’m not going to give you the answer right away. Instead, I will tell you how to find it without studying a thousand pages of the standard.

To begin with, let’s add some debugging:

#include <iostream> struct A { A (int i) { std::cout << 'A';} }; struct B { B (A a) { std::cout << 'B';} }; int main () { int i = 1; B b(A(i)); // (1) return 0; }

If we try to run this code, it turns out that nothing is printed at all. But if we replace the first line with

B b(A(1)); Suddenly, everything starts to work..

Now, let’s look closely at the compiler output, when warnings are enabled.

$ g++ -W -Wall test.cpp x.cpp:2: warning: unused parameter ‘i’ x.cpp:6: warning: unused parameter ‘a’ x.cpp: In function ‘int main()’: x.cpp:10: warning: unused variable ‘i’

As for the first two lines, everything is quite clear. Indeed, parameters of constructors are not used. But the last line looks really strange. How come variable i is not used, while we use it in the next line?

I guess this information could be enough to answer the question after some thinking. But if there are no right thoughts coming to our mind, why not ask the compiler? That’s when RTTI comes to the rescue.

#include <iostream> #include <typeinfo> struct A { A (int i) {} }; struct B { B (A a) {} }; int main () { int i = 1; B b(A(i)); // (1) std::cout << typeid(b).name() << std::endl; return 0; }

When compiling with GCC 4.3, the result of this program is the following string:

F1B1AE It contains the information about the variable type (of course, another compiler will print a different string, the type_info::name() output format is not described in the standard and left here to the discretion of the developer). c++filt will help us to find out what these letters and numbers mean.

$ c++filt -t F1B1AE B ()(A)

Here’s the answer: it is a function that accepts a parameter of type A and returns a value of type B.

The Reason

It remains to understand why our line is interpreted in such an unexpected way. The thing is that in the declaration of the variable type, the extra parentheses around the name are ignored. For instance, we can write

int (v); and this will mean exactly the same thing as

int v; Therefore, we can rewrite the first line without changing its meaning, by removing an extra pair of parentheses:

B b(A i); We can see now that b is the declaration of a function with one argument of type A, and that this function returns a value of type B.

At the same time, we have explained the strange warning about the unused variable i. And really, it has no relation to the formal parameter i.

Workarounds

It remains to explain the compiler what we actually want from it. That is, to get a variable of type B, initialized by a variable of type A. The easiest way is to add an extra parentheses, like this:

B b((A(i))); or like this:

B b((A)(i)); This should be enough to convince the parser that it is not a declaration of a function.

As an alternative, we can call a constructor by using an assignment operator, unless the constructor is declared as explicit:

B b = A(i); Despite the = operator, there’s no extra copy takes place here (as can be easily seen by introducing a private copy constructor in class B).

But we can also introduce an additional variable:

A a(i); B b(a);

However, this will require an extra copy of variable a, which is acceptable in many cases.

Choose the method that seems more clear to you :)

Inspired by the post on StackOverflow.