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.

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.

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.

Nice recap on the most vexing parse problem. Just a minor nitpick: when you say

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)

It’s (almost always) true that no extra copy takes place, but it’s not true that you can have a private (or deleted since C++11) copy constructor as the standard explicitly requires a copy constructor to be accessible (can’t remember the exact wording, but that’s the gist of it) even though the compiler is allowed not to call it even if it has side effects.
In other words, the standard allows to avoid calling a copy constructor during a copy-initialization, even if you rely on its side effects (e.g. the copy constructor does I/O), but a copy constructor must nonetheless be eligible for calling, otherwise the copy-initialization statement is ill-formed

Most of us work with strings one way or another. There’s no way to avoid them — when writing code, you’re doomed to concatinate strings every day, split them into parts and access certain characters by index. We are used to the fact that strings are fixed-length arrays of characters, which leads to certain limitations when working with them. For instance, we cannot quickly concatenate two strings. To do this, we will at first need to allocate the required amount of memory, and then copy there the data from the concatenated strings.