Anonymous object with one argument cannot be declared
There is this code:
class SomeClass
{
public:
SomeClass(){}
SomeClass(SomeClass& b){}
SomeClass(SomeClass&b, SomeClass& c){}
};
int main()
{
SomeClass a;
SomeClass(); // works all right
//SomeClass(a); error: redeclaration of ‘SomeClass a’
SomeClass(a, a); // works all right
return 0;
}
The anonymous object SomeClass with 0 and 2 parameters can be declared, however it cannot be declared with only one argument. I assume that the entry
SomeClass(a);
coincides with
SomeClass a;
How do I create an anonymous object with one argument?
You can create a temporary object in your own statement with something like:
(SomeClass)a;
or
(SomeClass(a));
As you noticed, parentheses are necessary to disambiguate between a declaration and an expression.
You can create this anonymouse object like this:
(SomeClass(a));
This removes the ambiguity as it cannot be a declaration a
.
(SomeClass a); // Error: this can't be a declaration because of the parentheses
// but what else should it be?
In this context, the parentheses are superfluous, which means
SomeClass(a); //declaration of a
is exactly equivalent to
SomeClass a; //declaration of a
which again is equivalent to these:
SomeClass((a))); //declaration of a
SomeClass(((a))); //declaration of a
SomeClass((((a)))); //declaration of a
SomeClass(((((a))))); //declaration of a
They all declare a name variable a
and type SomeClass
.
In general, you avoid the most annoying parsing by writing code with the same effect as what you wanted to write, but it cannot be parsed as a declaration.
This is often done by adding parentheses.
In this case, (SomeClass(a));
will do, or(void) SomeClass(a);
Your guess is correct.
You simply cannot create a temporary object with a single constructor argument in a context where the same statement can be a declaration. The grammar makes this ambiguous (or, it would be ambiguous if the behavior you see was not defined to take precedence).
Why don't you give the object a name?
SomeClass obj(a);
Or, if you have a reason to immediately destroy the object (this is sometimes useful, for example boost::this_thread::interruption_point
, although this takes no arguments), you can still create a temporary but defuse statement:
(SomeClass(a)); // the parens prevent this from being a declarative statement
In some scenarios, you can also use C-style casts:
(SomeClass)a;
But hopefully your constructor SomeClass
is actually marked explicit
and we prefer not to use C-style casts anyway.
This problem does not arise in other contexts where temporal might make more sense:
std::cout << SomeClass(a); // *can't* be a decl of a `SomeClass` called `a`