I have the following piece of code.
class A {
public:
A(int) {
}
};
int a;
int main() {
A(a); // Line 'a
return 0;
}
What I want to do on line 'a is to create a temporary A with constructor A::A(int). I know it's going to destruct immediately. That's what I want. But it seems the compiler is doing something equivalent to A a, defining variable a as of class A and initialize it using constructor A::A(). Of course it doesn't exist, hence the compiler error.
However, if I change my code to the following.
class A {
public:
A(int) {
}
};
void f(A) {
}
int a;
int main() {
f(A(a));
return 0;
}
It works fine now. The compiler constructs a temporary A and use it to call f.
Why is A(a) different in both contexts? How is it stated in the standard or for some obscure reason? How can I construct a temporary object as in the first code sample?
This is another instance of the "everything that can be a declaration is a declaration" rule. [stmt.ambig]/p1:
There is an ambiguity in the grammar involving expression-statements
and declarations: An expression-statement with a function-style
explicit type conversion (5.2.3) as its leftmost subexpression can be
indistinguishable from a declaration where the first declarator
starts with a (. In those cases the statement is a declaration.
The standard provides the following examples:
Assuming T is a simple-type-specifier,
T(a)->m = 7; // expression-statement
T(a)++; // expression-statement
T(a,5)<<c; // expression-statement
T(*d)(int); // declaration
T(e)[5]; // declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration
In the last example above, g, which is a pointer to T, is initialized
to double(3). This is of course ill-formed for semantic reasons, but
that does not affect the syntactic analysis.
and also:
class T {
// ...
public:
T();
T(int);
T(int, int);
};
T(a); // declaration
T(*b)(); // declaration
T(c)=7; // declaration
T(d),e,f=3; // declaration
extern int h;
T(g)(h,2); // declaration
The simplest way to disambiguate is probably an extra set of parentheses. (A(a)); is unambiguously an expression-statement.
I could not think of a way to create a temporary without using it in some call, like you did with the function.
Why don't you want to create a named variable instead? It's lifecycle will be exactly the same as your "temporary", given how you try to declare it.
If you really want to control the destruction of your object, you could always encapsulate it in a block: { A tmp(a); } // temporary A object
The thing is... I don't see the point of doing that. Why would you want to create a temporary object without using it? It usually means that your object creation or destruction has some side effects that you want to trigger. This is a really bad idea! You should move the side effects to a function and simply call it.
Related
class Act {
protected:
string Owner;
double Balance;
public:
explicit Act(int = 0);
double getBalance() { return Balance; };
};
What is the meaning of line of constructor Act(int =0); Need what int=0 would do here.
Explanation
explicit Act (int = 0);
defines a constructor, that construct an Act from an int parameter. The =0 means that if the parameter can be omitted, it will have a default value of 0. The explicit keyword tells the compiler not to use this constructor for making an implicit conversion.
Examples of use
As it is:
Act a1; // Will generate the same code as Act a1(0);
Act a5{}; // Same as above, but using the braced initialization
Act a2(12); // Obvious
Act a3=13; // Ouch ! Compiler error because of explicit
Act a4 = Act(13); // Ok, because now the call is explicit
If you wouldn't have the explicit keyword, then this line would be ok
Act a3=13; // If not explicit, this is the same than Act a3=Act(13);
Important remarks
The default value is not something that is part of the constructor itself, but a behavior that is defined on the caller side, based on the declaration of the constructor known by the caller.
This means that you could include declare the class with different default values in different compilation units. Although strange, this is perfectly valid.
Note that the absence of parameter name in the declaration is not a problem either, because, the parameter name can be declared within the constructor definition:
Act::Act(int x) : Balance((double)x) {
cout <<"Constructor Act with parameter "<<x<<endl;
}
Finally, note that if you want to use the default value by omitting the parameter, but that your constructor has only one parameter, you should either use the syntax form a1 or a5 in the examples above. You should however not use the syntax with empty parentheses because this would be understood as a function declaration:
Act a0(); // Ouch !! function declaration ! Use a0 or a0{} instead.
In order to address your question we must break down what the line does.
The line calls the constructor for the class Act, the int which has no variable name requires the constructor to take an int. However the =0 part is the default parameter telling the constructor that you don't need the int just place a 0 there.
I was digging in somebody else's code where I noticed he assigns the public/private members of a class in the following way:
myMemberVar(Value);
instead of
myMemberVal=Value;
I'm wondering if this way of assigning is normal and can be really used interchangebally.
It's likely that you're looking at initialisations in the member initialisation list.
struct A
{
int x, y;
A()
: x(42) // <-- here
, y(12) // <-- and here
{}
{};
These are not "assignments", any more than the following are assignments:
void foo()
{
int x = 42;
int y = 42;
}
But recall that the C++03 initialisation syntax (as opposed to the above confusing, legacy, looks-like-assignment syntax†) is:
void foo()
{
int x(42);
int y(42);
}
And, going further, since C++11:
void foo()
{
int x{42};
int y{42};
}
And that's the syntax that's required in the member initialisation list.
Note that this means they're not generally interchangeable: only in an initialisation! Usually when you write = you're performing assignment and this initialisation syntax would be invalid there.
† Don't worry, I still prefer it too!
That is the syntax for construction, not assignment.
The first snippet of code doesn't assign anything; it attempts to call myMemberVar like a function.
Perhaps the real code was in the initialiser list of a constructor:
MyClass() : myMemberVar(Value) {}
while the second was in the constructor body:
MyClass() {
myMemberVar = Value;
}
The difference here is that the first performs direct-initialisation, not assignment; the second performs default-initialisation followed by assignment.
For simple types, both have the same effect, and can be regarded as interchangable. For class types, they might call different user-defined functions: a conversion/copy/move constructor in the first case, and a default constructor followed by an assignment operator in the second. Depending on how those functions are defined, the two options may have different effects or performance characteristics, and may not be possible if the required functions aren't accessible.
I am faced with a very puzzling issue. I am trying to construct an object using a variable as a parameter.
Have a look at this code please:
#include <iostream>
class A {
public:
A() : val(0) {};
A(int v) : val(v) {};
private:
int val;
};
main() {
int number;
A a; /* GOOD, object of type A, created without arguments */
A b(2); /* GOOD, object of type A, created with one argument */
A c(); /* BAD, C++ thinks this is declaration of
a function returning class A as a type */
A(d); /* GOOD, object of type A again; no arguments */
A(number); /* BAD, tries to re-declare "number" as object of type A */
}
I think I do understand why objects "a", "b" and "d" can be created, whereas the rest can not.
But I would really need the syntax of the last declaration, i.e.
A(number);
to create a temporary object, to pass as an argument to another object.
Any idea how to work around it?
Kind regards
Your intention is to create a temporary object, but this object would also be anonymous : you have no way to refer to it after the semicolon.
There is no point in creating an anonymous temporary object just to discard it. You have to instantiate your temporary directly at the call site of the ctor/method that will consume it.
Solution
To pass an anonymous temporary object to a function, you actually need to instantiate it inside the arguments' list :
functionExpectingA(A(number));
For the line of "c declaration", you are poking at the most vexing parse. If you actually need to pass a default constructed A object as an argument to another object constructor, you need to add another pair of braces to do the trick (so the compiler can distinguish it from a function declaration) :
class OtherClass
{
public:
OtherClass(A a)
{
//...
};
};
OtherClass obj((A()));
^ ^
EDIT #1 : jrok pointed out that the argument given to A constructor is not enough to resolve the ambiguity.
If you need to pass an anonymous temporary object that is built with an argument, there is no ambiguity (so no need for the extra parentheses), you still need the parentheses around the anonymous object construction.:
OtherClass obj((A(number)));
C heritage : a single argument is not enough
EDIT #2 : "why giving a single argument to A constructor does not resolve the ambiguity".
What happens with OtherClass obj(A(number)); ?
This is a declaration for a function named obj, taking an A object as its unique argument. This argument is named number.
i.e: It is exactly equivalent to OtherClass obj(A number);. Of course, you can omit the argument name at function declaration. So it is also sementically equivalent to OtherClass obj(A);
The syntax with parentheses around the object name is inherited from C :
int(a); // declares (and defines) a as an int.
int a; // strictly equivalent.
What with more arguments to the constructor then ?
If you added a ctor to OtherClass taking two (or more) arguments :
OtherClass(A a1, A a2)
{
//...
};
Then this syntax :
A arg1, arg2;
OtherClass obj(A(arg1, arg2));
Would this time actually declare obj as an instance of OtherClass.
This is because A(arg1, arg2) cannot be interpreted as name declaration for an A. So it is actually parsed as the construction of an anonymous A object, using the constructor with 2 parameters.
I have a custom class that I want to behave like a built-in type.
However I have noticed that you can initialise a const variable of that class without providing an initial value. My class currently has an empty default constructor.
Here is a comparison of int and my class foo:
int a; // Valid
int a = 1; // Valid
const int a = 1; // Valid
const int a; // Error
foo a; // Valid
foo a = 1; // Valid
const foo a = 1; // Valid
const foo a; // Should cause an error, but it compiles
As you can see I need to prevent
const foo a;
from compiling.
Any ideas from C++ gurus?
It compiles only if it has a default constructor, and it compiles because it has it, which means that it is initialized. If you don't want that line to compile, just disable the default constructor (will also make foo a; an error as an unwanted side effect). Without a definition of foo or what you want to do, this is as far as I can get.
I don't think there is any way of achieving what you want (i.e. allow the non-const variable to be default initialized, while having the const version fail compilation and allowing the other use cases --that require providing constructors)
The rules of C++ simply say that default-initialization (e.g. new T;) and value-initialization (e.g. new T();) are the same for objects of class type, but not for objects of fundamental type.
There's nothing you can do to "override" this distinction. It's a fundamental part of the grammar. If your class is value-initializable, then it is also default-initializable.
There is a sort-of exception for classes without any user-defined constructors: In that case, initialization of members is done recursively (so if you default-init the object, it tries to default-init all members), and this will fail if any of the class members are themselves fundamental, or again of this nature.
For example, consider the following two classes:
struct Foo { int a; int b; };
struct Goo { int a; int b; Goo(){} };
//const Foo x; // error
const Goo y; // OK
The implicit constructor for Foo is rejected because it doesn't initialize the fundamental members. However, y is happily default-initialized, and y.a and y.b are now "intentionally left blank".
But unless your class doesn't have any user-defined constructors, this information won't help you. You cannot "forward" the initialization type to a member (like Foo() : INIT_SAME_AS_SELF(a), b() { }).
#include<iostream>
class name
{
public:
int a;
name():a(0){};
};
void add(name * pname)
{
pname = NULL;
}
int main()
{
name varName();
name * pName = new name();
add(pName);
add(&varName);//error C2664: 'add' : cannot convert parameter 1 from 'name __cdecl *)(void)' to 'name *'
}
The error is on the first line of the main function:
name varName();
You are not creating an instance of class name with the default constructor, you are actually declaring a new function called varName, with no parameters, which returns a name instance.
You should instead write:
name varName;
I think it's worth telling you about a similar problem, that also causes trouble:
struct foo { };
struct bar { bar(foo f); };
int main() {
// does *not* create a bar object initialized by a default constructed
// foo object.
bar b(foo());
}
What b really is is a function that returns a bar and takes as first argument a pointer to a function that returns a foo taking no arguments. It's the same as:
bar b(foo(*)());
If you want to create a bar object initialized by a default constructed foo, put parentheses around the argument. That makes it doesn't look like a function declaration anymore, and the compiler will interpret it like you want:
bar b((foo()));
There are also non-obvious cases where a compiler error should be risen. GCC gets this wrong, but Comeau gets it right again. Consider the following snippet
struct foo {
static bool const value = false;
};
int main() {
int v(int(foo::value));
}
You will probably expect that this takes the static constant, and casts it to int, initializing the v variable to 0? No, it won't according to the Standard, because the initializer can be interpreted as a declaration, according to pure syntax analysis, as the following shows
struct foo {
static int value;
};
// valid, parentheses are redundant! Defines `foo::value`.
int (foo::value);
Whenever the initializer can be interpreted as a declaration, in such a situation whole the declaration will declare a function. So, the line in main declares a function like the following, omitting the redundant and meaningless parentheses
int v(int foo::value);
And this will cause a compiler error when parsing the function declaration, because a function parameter name may not be qualified.
It's also worth noting that your add() function doesn't have any lasting effects -- all it's doing is assigning a value to pname, which is a copy of the pointer you pass into it. If you want to actually have that assignment stick, you would need to pass the pointer by reference as "name*& pname".
name varName();
is interpreted as a local function declaration. To invoke the default constructor, use
name varName;
instead. Most vexing, yes.