I’ve always been taught that
1. Class c(arg);
and
2. Class c = arg;
are two totally equivalent statements, but look at this situation.
#include <iostream>
class Intermediary {
};
class Left {
public:
Left(const Intermediary &) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class Right {
public:
// The argument is there just so that the example can work, see below
Right(int) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
operator Intermediary () const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return Intermediary();
}
};
Now if I do this:
Left l = Right(0);
The compiler will complain
error: conversion from Right to non-scalar type Left requested
But if I do this:
Left l(Right(0));
Then everything compiles and the output is
Right::Right(int)
Right::operator Intermediary() const
Left::Left(const Intermediary&)
However, if I do this:
Left l = (Intermediary)Right(0);
then everything compiles again and the output is just like the one above.
So obviously
1. Class c(arg);
and
2. Class c = arg;
are not the same, but why not, and what’s the difference? I couldn’t find anything about this online.
It turns out they are not equivalent. The first one constructs the
Class cout of anarg, while the second one constructs aClassout of anargand then copy-constructsClass cout of it. Note that the implementation is allowed to ellide that copy, and it usually does.This requires a conversion from
RighttoIntermediary, and one fromIntermediarytoLeft. This two sequential user defined conversions are not allowed by the standard, you have to do at least one of them explicit as you do with: