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;
}
Anonymous object of SomeClass with 0 and 2 parameters can be declared, however it cannot be declared with only 1 argument. I assume that writing
SomeClass(a);
is the same as
SomeClass a;
How to create anonymous object with one argument?
You can construct a temporary object in a statement of its own with something like:
(SomeClass)a;
or
(SomeClass(a));
As you've observed, the parentheses are needed to resolve the ambiguity between a declaration and an expression statement.
You can create that anonymouse object as the following:
(SomeClass(a));
This resolves the ambiguity since it can't be a declaration of a.
(SomeClass a); // Error: this can't be a declaration because of the parentheses
// but what else should it be?
In that context, the braces are superfluous, which means
SomeClass(a); //declaration of a
is exactly equivalent to
SomeClass a; //declaration of a
which is again equivalent to these:
SomeClass((a))); //declaration of a
SomeClass(((a))); //declaration of a
SomeClass((((a)))); //declaration of a
SomeClass(((((a))))); //declaration of a
All of these declare a variable of name a and type SomeClass.
In general, you avoid the most vexing parse by writing code with the same effect as what you wanted to write, but that can't be parsed as a declaration.
Often, this is done by adding parentheses.
In this case (SomeClass(a)); will do, or (void) SomeClass(a);
Your assumption is correct.
You simply cannot create a temporary object with a single constructor argument in a context where the same statement could be a declaration. The grammar makes it ambiguous (or, it would be ambiguous if the behaviour you're seeing weren't defined to take precedence).
Why not give the object a name, instead?
SomeClass obj(a);
Or, if you have a reason to want the object to be destroyed immediately (sometimes this is useful; e.g. a boost::this_thread::interruption_point, though that takes no arguments), you can still create a temporary but de-ambiguate the statement:
(SomeClass(a)); // the parens prevent this from being a declarative statement
In some scenarios you may also be able to use C-style casts:
(SomeClass)a;
But, hopefully, your SomeClass constructor is actually marked explicit, and we prefer not to use C-style casts anyway.
This problem doesn't arise in other contexts, ones in which a temporary might make more sense anyway:
std::cout << SomeClass(a); // *can't* be a decl of a `SomeClass` called `a`
Related
I am studying some advance c++ code and I am struggling to understand what the author was trying to define in the scope of the constructor he defines outside the class:
The code looks something like this:
class myclass(){} // defined somewhere else.
myclass::myclass(const char *x, const char *y, const char *z):
variable_A(x), variable_B(y), variable_C(z)
{
runsomefunction();
runanotherfunction();
}
The runsomefunction is not defined in the class.
Essentially what I need to know is what can I do in the scope (i.e. in the curly braces after the constructor initialisers) of a constructor formed in this manner. Or rather, what do people do in those braces.
Note that: the definition of the cluster in this example is incomplete. The original code is quite lengthy and my question is just specific to the scope of the constructor that looks like this.
The example is ill-formed because the class definition doesn't declare the constructor that is defined, nor the sub objects that the constructor initialises.
what the author was trying to define
The author has defined a class, and a constructor.
Essentially what I need to know is what can I do in the scope (i.e. in the curly braces after the constructor initialisers)
Those curly braces are a block statement. You can do things there that you could do in any block statements, and furthermore things that you can do in member functions. Constructor is a (special) member function.
Here are some more examples of block statements:
void example_function()
{ // <-- beginning of a block statement
if (something) // if-statement is something that
// can be only within block statements
{ // <-- beginning of a block statement
// An if-statement doesn't necessarily
// contain a block statement, but
// it is quite typical.
}
}
It is quite rare to need to do anything in the block statement of a constructor, but when you need to, it's there for you to do what you need.
Here is some code I wrote to illustrate my question:
struct Foo
{
Foo() {}
Foo( Foo && );
Foo( const Foo & ) = delete;
};
Foo GetFoo()
{
return Foo();
}
int main()
{
Foo f = GetFoo();
}
The deleted copy constructor prevents an implicit default move constructor, so I have to explicitely declare one. But I am neither using "= default" nor providing an implementation for it, yet the whole thing compiles and links properly. If I remove the declaration, it won't compile anymore.
I find it really surprising that the linker isn't complaining about the missing move constructor. Could you please help me understand why?
When initializing a variable in the form type identifier = Function(), the compiler affirms that a copy/move constructor is declared as usable, and then ignores it and tries to construct from the right side directly ("copy/move elision"). Then it has Function construct the variable directly into main, to skip a move/copy (this is "return value optimization"). These sort of work together and bypass any and all moves/copies, and Function ends up constructing f directly. Since the move constructor wasn't actually used, the linker didn't look for it, and thus failed to notice the missing definition.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
In C++ classes, why the semi-colon after the closing brace
This is something I have wondered about for quite some time, why do you have to put a semicolon after the closing bracket of a class, struct or enum in c++?
Worse (or the actual question), why does compilers emit errors about it when they could simply issue a warning?
Is it really important to put that semicolon there and if, why?
It's a leftover from C. You can declare variables after cladd/struct/enum declaration. the code:
class A{};
A a;
Is identical to:
class A{} a;
The compiler needs the ; to know you don't want to declare variables after the class declaration.
Is it really important to put that semicolon there and if, why?
Yes. This can be useful sometime.
You can define a struct, and can declare an object as:
struct A
{
//members
} obj;
obj is an object of type A, and you declare this just as shown above. It is in same way you put semicolon after declaring variables, such as:
int i; //declares i of type int
std::string s; //declares s of type std::string
struct {int x,y,z;} point; //declares point of an unnamed struct type
Here first two declarations look very familiar, but the last one looks slightly unfamiliar, as it defines an unnamed struct, and simultaneously declares an object called point of the unnamed struct.
The bottomline is that you put a semicolon after declaring objects uniformly, no matter how you declare the objects, no matter what their types are.
Not only that you can even typedef in a uniform way:
typedef int my_int;
typedef std::string my_string;
typedef struct {int x,y,z;} my_point;
Now all of these my_int, my_string, and my_point are types.
But when you do neither of them (i.e neither declaring objects, nor defining typedefs), then you simply leave the place as such, blank, with no declaration/definition whatsoever. But the point to be noted is that it gives you an interesting and useful feature all along.
Class, struct and enums definitions are that, definitions. And definitions in C++, as in C, must be finished with a semicolon.
If you do not put it there would be a lot of ambiguities:
struct X
{
} //no ;
foo() //no return value
{
}
This is read as a function foo that returns a struct, not an struct and a function that returns an (ommited) integer. This is valid C, but not C++.
int *x;
void foo()
{
struct S { } //no ;
*x = 3; // <--- what is this?
}
Is the second x a local variable of type pointer-to-S, or is a reference to the global x? You simply cannot tell.
There are a lot of other examples, probably you can think a few, if you try.
why do you have to put a semi colon after the closing bracket of a class, struct or enum in c++?
Real answer, Because the C++ Standard says so. The language was designed in a way so that every declaration must end with a ;.
An class object can be declared as:
class MyClass
{
//Members
}obj;
And hence the ; at the end of the brace.
Worse (or the actual question), why does compilers emit errors about it when they could simply issue a warning?
The compiler issues a warning when it doubts something might be wrong or potentially hazardous
The compiler issues an error when the program does not follow the syntactic guidelines laid out by the standard, leaving out the semi colon in the cases you mentioned violates the syntax rules mentioned by the C++ standard and hence the error.
void func() {assert(0);}
int main () {void func();}
The above code does not call func(), or at least does not reach the assertion. Not that I really need to know, but I'm just curious, what is going on here?
You're declaring a prototype for a function named func which returns nothing and takes no arguments. That's (one of) the subtle difference between function calls and function prototypes. Notice that the line above main, the void func() {assert(0);}, has no effect on whether this is a prototype or a call. You could remove it and the code would do the same thing - that is, nothing.
This also tells you that you can redeclare function prototypes. You could even have this:
int main() {
void blah();
void blah();
void blah();
void blah();
}
And the code would still do what it did before - nothing.
If you leave off the void, it would call the function.
Also, notice that in the case of a function which takes parameters, this:
int main() { func(4); }
would not turn into a prototype if you added void before it like this:
int main() { void func(4); }
it would just produce a syntax error.
As others have pointed out, the line
void func();
inside of main is treated as a function prototype rather than a call to the function func. In C and C++, you can declare function prototypes inside of functions if you wish, though it's rarely done in practice.
The fact that this is legal causes all sorts of headaches for programmers. For example, if you rewrote the code as
(void) func();
Then this would compile as a call to func whose return type is explicitly casted to void to indicate "I don't care about this return value." In other words, this set of parentheses changes the declaration into a statement.
In C++, this problem can be compounded by the fact that this code below is a function prototype, not a variable declaration invoking the default constructor:
Object myObject();
Though
Object myObject(137);
does create the object and pass 137 into its constructor, and
Object myObject;
creates the object without calling the constructor.
There is an awful edge case of the language called the "most vexing parse" that arises when trying to declare an object while calling its constructor. For example, this code is legal C++, but it's a function declaration rather than a variable declaration:
set<int> mySet(istream_iterator<int>(cin), istream_iterator<int>());
The problem is that this could be parsed as a function declaration rather than a creation of an object that accepts two temporary istream_iterator<int>s as parameters. To fix this, in C++ you'd have to write
set<int> mySet(istream_iterator<int>(cin), (istream_iterator<int>()));
Where, as above, the extra parentheses forcibly disambiguate the statement from being a function prototype to being a declaration.
Hope this helps!
You can declare functions, even when it's unnecessary. That's what you've done, re-declared the function.
You are declaring a local function void func() inside main().
The void statement indicates the compiler that it is a declaration and not a function call. So, remove the void, your function will be called.
In the code below, why does the compiler not complain for mClass2?
class CMyClass{
private:
CMyClass(){}
};
void TestMethod(){
CMyClass mClass1; //Fails.
CMyClass mClass2(); //Works.
}
Because you've just declared a function mClass2 of zero arguments that returns a CMyClass. That's a valid option since there could be, say, a static CMyClass instance which that function has access to. Note that CMyClass still has a public copy constructor.
(To convince yourself, compile this module to assembler and observe that commenting out the line CMyClass mClass2(); produces the same output.)
Because it is declaring a function and not calling the constructor as you think.
This is called as the Most Vexing Parse in c++.
CMyClass mClass2();
declares a function mClass2() which takes no parameter and returns CMyClass
The second one is a function declaration.
People ought to move to the uniform syntax initialization in C++0x/C++11 using the {} brackets instead which removes this issue.
Class C{};
http://www2.research.att.com/~bs/C++0xFAQ.html#uniform-init