This sample program shows how a different constructor will be called depending on whether you pass in a local variable, a global variable, or an anonymous variable. What is going on here?
std::string globalStr;
class aClass{
public:
aClass(std::string s){
std::cout << "1-arg constructor" << std::endl;
}
aClass(){
std::cout << "default constructor" << std::endl;
}
void puke(){
std::cout << "puke" << std::endl;
}
};
int main(int argc, char ** argv){
std::string localStr;
//aClass(localStr); //this line does not compile
aClass(globalStr); //prints "default constructor"
aClass(""); //prints "1-arg constructor"
aClass(std::string("")); //also prints "1-arg constructor"
globalStr.puke(); //compiles, even though std::string cant puke.
}
Given that I can call globalStr.puke()
, I'm guessing that by calling aClass(globalStr);
, it is creating a local variable named globalStr
of type aClass
that is being used instead of the global globalStr
. Calling aClass(localStr);
tries to do the same thing, but fails to compile because localStr
is already declared as a std::string
. Is it possible to create an anonymous instance of a class by calling its 1-arg constructor with a non-constant expression? Who decided that type(variableName);
should be an acceptable way to define a variable named variableName
?
aClass(localStr); //this line does not compile
This tries to declare a variable of type aClass
named localStr
. The syntax is terrible, I agree, but it's way too late for that [changing the standard] now.
aClass(globalStr); //prints "default constructor"
This declares one called globalStr
. This globalStr
variable hides the global one.
aClass(""); //prints "1-arg constructor"
This creates a temporary object of type aClass
.
aClass(std::string("")); //also prints "1-arg constructor"
This also creates a temporary.
globalStr.puke(); //compiles, even though std::string cant puke.
This uses the globalStr
in main
, which is consistent with every other instance of shadowing.
Is it possible to create an anonymous instance of a class by calling its 1-arg constructor with a non-constant expression?
Yes, I can think of four ways:
aClass{localStr}; // C++11 list-initialization, often called "uniform initialization"
(void)aClass(localStr); // The regular "discard this result" syntax from C.
void(aClass(localStr)); // Another way of writing the second line with C++.
(aClass(localStr)); // The parentheses prevent this from being a valid declaration.
As a side note, this syntax can often be the cause of the Most Vexing Parse. For example, the following declares a function foo
that returns aClass
, with one parameter localStr
of type std::string
:
aClass foo(std::string(localStr));
Indeed it's the same rule that's responsible for your problems - If something can be parsed as a valid declaration, it must be. That is why aClass(localStr);
is a declaration and not a statement consisting of a lone expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With