trick question regarding declaration syntax in C++ - c++

Have a look here:
In the following code, what would be the type of b?
struct A {
A (int i) {}
};
struct B {
B (A a) {}
};
int main () {
int i = 1;
B b(A(i)); // what would be the type of b
return 0;
}
I'll appreciate it if anybody could explain to me thoroughly why would such syntax exist :)
Thanks.

One of C's warts (and C++ inherits it (and makes it worse)) is that there is no special syntax for introducing a declaration. This means declarations often look like executable code. Another example:
A * a;
Is this multiplying A by a, or is it declaring something? In order to make sense of this line you have to know that A is the name of a type.
The basic rule in C++ is that if something can be parsed as a declaration, it is. In this instance it leads to a strange and surprising result. Function declarations look a lot like function calls, and in particular the ( after the A can be thought of in a couple of ways.
You can get around this in this example with extra parenthesis that remove the compiler's ability to parse the code as a declaration.
B b((A(i)));
In C this isn't ambiguous because there is no function style of constructor call because there are no constructors. A is either the name of a type, or it's the name of a function. It can't be both.

It is a local function declaration according to C++ Standard 8.2/1. You could use implicit form of constructor to avoid this or the following:
B b(A(i)); // is equal to B b( A i );
// ---
// to declare variable of type B write:
B b = A(i);
// explicit form if you want:
B b( static_cast<A>(A(i)) );
// or
B b( (A)i );
C++ Standard 8.2/1:
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8
can also occur in the context of a declaration. In that context, the choice is between a function declaration
with a redundant set of parentheses around a parameter name and an object declaration with a function-style
cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any con-
struct that could possibly be a declaration a declaration.

B b(A(i));
is equivalent to
B b(A i);
- the parenthesis around the argument name are optional -, which is equivalent to
B b(A);
- the parameter name is optional in function declarations. Hence it is a function declaration.
Typically you run into it with
X x();
- not default constructor as expected -, but there are more complicated cases when using temporaries all the way, e.g
vector<int> v(istream_iterator<int>(cin), istream_iterator<int>());

Related

Function style casting using the `new T()` operator in C++

Here is an example of a simple function style casting done by int(a):
float a = 5.0;
int b = int(a);
More info from cpprefrenece:
The functional cast expression consists of a simple type specifier or a typedef specifier followed by a single expression in parentheses.
I have 2 questions:
1) would using the new operator still count as a functional cast?
int* b = new int(a);
2) Assuming test is a class, then test t = test(1); is a function style casting to test but test t = test(1, 2); isn't because it has more than 1 expression in parenthesis?
would using the new operator still count as a functional cast?
No, the use of the new operator(like you used in your example) is not a use case of functional cast.
test t = test(1, 2); isn't because it has more than 1 expression in parenthesis?
Both test t = test(1); and test t = test(1,2); are copy initializations. Now, the subexpression test(1) is indeed a functional cast where the appropriate test constructor will be used. While the subexpression test(1, 2) is not as it has more than a single expression inside parenthesis.
1) New expression
A new-expression is a special case of... a new-expression. Nothing less, nothing more. It results in creation of object of given type in dynamic storage and , for class-types, in a call to constructor with given argument list. For trivial types new-expression provides an initializer.
A new-expression isn't a cast, albeit initializing parameters from argument list given in parenthesis may involve implicit casts. If returned result of new-expression wasn't used, the created object would continue to exist. And unless there is a curious contingency involved, it would not be correctly freed.
A functional cast would produce an xvalue, an object which would expire at end of enclosing expression.
C++ parser by design is a "greedy" parser. It doesn't try to single out every token first, it's a complex algorithm to match statements to whole patterns, as longer as possible, appropriate for current context (and context may change in result). The "greedy" nature becomes obvious in case of some ill-formed or ambiguous code. As a rule, if something can be parsed wrong, it will be parsed wrong, but not until whole statement would be analyzed.
Speaking of functional cast, typename(name) syntax may appear in declarations of variables or types, which result in following being a legal declaration:
int foo ( int (a) )
{
return a;
}
It's because since times of C we can declare some eldritch array of pointers as void (*(*f[])())(), which declares f as array of pointers to function returning a pointer to function returning void.
In result, initializing a variable with a functional cast may create an ambiguous code:
float fvar = 1.0f;
double dvar ( int(fvar) );
It declares a double(int) function named dvar! You wouldn't spot it, until you try assign to it:
auto v = dvar; // v is a pointer to function.
dvar = 4; // error
The declaration of dvar as whole matches BOTH a function declaration and a variable declaration. In this case compiler MUST choose wrongly, but diagnostics are optional. It's exacerbated by fact that C and C++ are allowing variable identifiers to match type names.
2) Initialization of object
Yes, the expression test(1) is a functional cast even if test is a class. By definition it results in considering an existing constructor to be called.
class test {
public:
test(int arg): b(arg) {}
protected:
int b;
};
Here constructor test(int) is called a conversion constructor as it can take exactly one parameter and its usage permits use of type-id test in functional cast - from int or int-compatible type. Constructors with more than one parameter without default value do not bear this name. For class test , te expression test(1,2) is ill-formed.
In fact, unless such constructor qualified as explicit, it would allow an implicit conversion:
struct test {
test(int a) {std::cout << "int " << a << std::endl;}
explicit test (float a) {std::cout << "float " << a << std::endl;}
};
int main()
{
test b = 1; // calls (int) constructor
test c = 2.0f; // calls (int) constructor
test d = test(3.0f); // function cast calls (float) constructor
}
P.S. C++11 allowed to escape functional cast syntax for initialization of class-type object. For above class it would be test{1}. But it also can be an aggregate initialization, if test would be trivial:
struct test {
int b;
};
test t = test{1};
New Operator
Yes. From the cppreference page on the new keyword
The object created by a new-expression is initialized according to the following rules:
For non-array type, ...
If initializer is a parenthesized list of arguments, the object is direct-initialized.
And if we check out the page on direct initialization, we find that syntax (3) on that page is
T ( other )
T ( arg1, arg2, ... )
initialization ... by functional cast or with a parenthesized expression list
So new is defined to perform direct initialization, and direct initialization is defined to perform a functional cast when necessary. There's more going on with regard to allocation in the background, but at some point down the line a functional cast may get performed.
More than 1 Expression
In regards to your second question, a "cast" is a conversion from one type to another. An initialization with one argument can be viewed as a cast, from the argument type T to the result type S. It makes no sense to think of test(1, 2) as a conversion from anything, since it takes two arguments and produces one value.

I do not understand why this compiles

I'm certainly missing something, but I do not understand why this compiles (with both g++ & clang++):
struct A
{
};
struct B
{
};
int main()
{
A a(B);
}
First of all, B is a type... not a value. How should I interpret this code?
It's interpreted as the declaration of a function named a, which takes one argument of type B and returns A.
It's simply a function declaration declaring a to be a function returning A and taking one unnamed parameter of type B.
It is valid because function declarations as opposed to function definitions are allowed within function definitions.
This issue is known as the most vexing parse. The line A a(B); can be interpreted as the declaration of a function named a returning an object of type A and taking an unnamed parameter of type B.
One way to avoid this issue is to use the uniform initialization syntax which was introduced in C++11, which consists in using braces instead of parenthesis: A a{B}; returns an error. The line is now interpreted as a variable declaration initialized with B, which is a type instead of a value.
Here's more information:
The Most Vexing Parse: How to Spot It and Fix It Quickly

Nonstatic member as a default argument of a nonstatic member function [duplicate]

This question already has answers here:
How to use a member variable as a default argument in C++?
(4 answers)
Closed 1 year ago.
struct X
{
X():mem(42){}
void f(int param = mem) //ERROR
{
//do something
}
private:
int mem;
};
Can anyone give me just one reason as to why this is illegal in C++?! That is to say, I know that it is an error, I know what the error means, I just can't understand why would this be illegal!
Your code (simplified):
struct X
{
int mem;
void f(int param = mem); //ERROR
};
You want to use a non-static member data as default value for a parameter of a member function. The first question which comes to mind is this : which specific instance of the class the default value mem belongs to?
X x1 = {100}; //mem = 100
X x2 = {200}; //mem = 200
x1.f(); //param is 100 or 200? or something else?
Your answer might be 100 as f() is invoked on the object x1 which has mem = 100. If so, then it requires the implementation to implement f() as:
void f(X* this, int param = this->mem);
which in turn requires the first argument to be initialized first before initialization of other argument. But the C++ standard doesn't specify any initialization order of the function arguments. Hence that isn't allowed. Its for the same reason that C++ Standard doesn't allow even this:
int f(int a, int b = a); //§8.3.6/9
In fact, §8.3.6/9 explicitly says,
Default arguments are evaluated each
time the function is called. The order
of evaluation of function arguments is
unspecified. Consequently, parameters
of a function shall not be used in
default argument expressions, even if
they are not evaluated.
And rest of the section is an interesting read.
An interesting topic related to "default" arguments (not related to this topic though):
Default argument in the middle of parameter list?
Default arguments have to be known at compile-time. When you talk about something like a function invocation, then the function is known at compile-time, even if the return value isn't, so the compiler can generate that code, but when you default to a member variable, the compiler doesn't know where to find that instance at compile-time, meaning that it would effectively have to pass a parameter (this) to find mem. Notice that you can't do something like void func(int i, int f = g(i)); and the two are effectively the same restriction.
I also think that this restriction is silly. But then, C++ is full of silly restrictions.
As DeadMG has mentioned above, somethig like
void func(int i, int f = g(i))
is illegal for the same reason. i suppose, however, that it is not simply a silly restriction. To allow such a construction, we need to restrict evaluation order for function parameters (as we need to calculate this before this->mem), but the c++ standard explicitly declines any assumptions on the evaluation order.
The accepted answer in the duplicate question is why, but the standard also explicitly states why this is so:
8.3.6/9:
"
Example: the declaration of X::mem1() in the following example is ill-formed because no object is supplied for the nonstatic member X::a used as an initializer.
int b;
class X
int a;
int mem1(int i = a); // error: nonstatic member a
// used as default argument
int mem2(int i = b); // OK: use X::b
static int b;
};
The declaration of X::mem2() is meaningful, however, since no object is needed to access the static member X::b. Classes, objects and members are described in clause 9.
"
... and since there exists no syntax to supply the object necessary to resolve the value of X::a at that point, it's effectively impossible to use non-static member variables as initializers for default arguments.
ISO C++ section 8.3.6/9
a nonstatic member shall not be used in a default argument expression, even if it
is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless it is used to form a pointer to member (5.3.1).
Also check out the example given in that section.
For one reason, because f is public, but mem is private. As such, code like this:
int main() {
X x;
x.f();
return 0;
}
...would involve outside code retrieving X's private data.
Aside from that, it would (or at least could) also make code generation a bit tricky. Normally, if the compiler is going to use a default argument, it gets the value it's going to pass as part of the function declaration. Generating code to pass that value as a parameter is trivial. When you might be passing a member of an object (possibly nested arbitrarily deeply) and then add in things like the possibility of it being a dependent name in a template, that might (for example) name another object with a conversion to the correct target type, and you have a recipe for making code generation pretty difficult. I don't know for sure, but I suspect somebody thought about things like that, and decided it was better to stay conservative, and possibly open thins up later, if a good reason was found to do so. Given the number of times I've seen problems arise from it, I'd guess it'll stay the way it is for a long time, simply because it rarely causes problems.
Compiler has to know addresses to maintain default values at compile time. Addresses of non-static member variables are unknown at compile time.
As all the other answers just discuss the problem, I thought I would post a solution.
As used in other languages without default arguments (Eg C# pre 4.0)
Simply use overloading to provide the same result:
struct X
{
X():mem(42){}
void f(int param)
{
//do something
}
void f()
{
f(mem);
}
private:
int mem;
};
Default arguments are evaluated in two distinct steps, in different contexts.
First, the name lookup for the default argument is performed in the context of the declaration.
Secondly, the evaluation of the default argument is performed in the context of the actual function call.
To keep the implementation from becoming overly complicated, some restrictions are applied to the expressions that can be used as default arguments.
Variables with non-static lifetime can't be used, because they might not exist at the time of the call.
Non-static member variables can't be used, because they need an (implicit) this-> qualification, which can typically not be evaluated at the call site.

Error C2228 when constructing boost::function object in constructor argument list

The code below does not compile in Visual C++ 2005.
class SomeClass {
public: boost::function<void()> func;
SomeClass(boost::function<void()> &func): func(func) { }
};
void someFunc() {
std::cout << "someFunc" << std::endl;
}
int main() {
SomeClass sc(boost::function<void()>(&someFunc));
sc.func(); // error C2228: left of '.func' must have class/struct/union
return 0;
}
If I put parentheses around the argument to the SomeClass constructor or constructs the boost::function object outside the argument list it compiles fine.
SomeClass sc((boost::function<void()>(&someFunc)));
// or
boost::function<void()> f(&someFunc);
SomeClass sc(f);
What is the problem with the previous code?
It's a function declaration for a function taking a reference to a boost:function <void()> and returning a SomeClass. You can memorize the following rule, which turns out to apply to many other such disambiguation cases. You can find descriptions of these cases in section 8.2 of the C++ Standard.
Any construct that could possibly be a declaration will be taken as a declaration
That means, the following will be taken as a parameter declaration, with superfluous parentheses
boost::function<void()>(&someFunc)
If you remove the parentheses, this will become clear
boost::function<void()> &someFunc
And thus, the whole declaration will not anymore declare an object, but a function
SomeClass sc(boost::function<void()> &someFunc);
To fix it, use the cast-notation
SomeClass sc((boost::function<void()>)&someFunc);
Or put parentheses around the whole expression, like you did.
Here is the Standard in all its glory from 8.2:
The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration. [Note: a declaration can be explicitly disambiguated by a nonfunction-style cast, by a = to indicate initialization or by removing the redundant parentheses around the parameter name. ]
Note that for controlling precedence, you are allowed to introduce parentheses just about anywhere, like in the following
int (((((((a))))))) = 3;
int (*(pa)) = &a;
This is known as "C++'s Most Vexing Parse" (from a book by Scott Meyers called Effective STL).
As answered above, the compiler prefers to interpret the problematic line as a function declaration.

C++ enum not properly recognized by compiler

Can anyone explain why the following code does not compile (on g++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-49))?
struct X {
public:
enum State { A, B, C };
X(State s) {}
};
int main()
{
X(X::A);
}
The message I get is:
jjj.cpp: In function 'int main()':
jjj.cpp:10: 'X X::A' is not a static member of 'struct X'
jjj.cpp:10: no matching function for call to 'X::X()'
jjj.cpp:1: candidates are: X::X(const X&)
jjj.cpp:5: X::X(X::State)`
Is this bad code or a compiler bug?
Problem solved by Neil+Konrad. See the comments to Neil's answer below.
You've forgot the variable name in your definition:
int main()
{
X my_x(X::A);
}
Your code confuses the compiler because syntactically it can't distinguish this from a function declaration (returning X and passing X::A as an argument). When in doubt, the C++ compiler always disambiguates in favour of a declaration.
The solution is to introduce redundant parentheses around the X since the compiler forbids parentheses around types (as opposed to constructo calls etc.):
(X(X::A));
X(X::A);
is being seen a s a function declaration. If you really want this code, use:
(X)(X::A);
Just to make it crystal clear what happens. Look at this example
int main() {
float a = 0;
{
int(a); // no-op?
a = 1;
}
cout << a;
}
What will it output? Well, it will output 0. The int(a) of above can be parsed in two different ways:
Cast to int and discard the result
Declare a variable called a. But ignore the parentheses around the identifier.
The compiler, when such a situation appears where a function-style cast is used in a statement and it looks like a declaration too, will always take it as a declaration. When it can't syntactically be a declaration (the compiler will look at the whole line to determine that), it will be taken to be an expression. Thus we are assigning to the inner a above, leaving the outer a at zero.
Now, your case is exactly that. You are trying (accidentally) to declare an identifier called A within a class called X:
X (X::A); // parsed as X X::A;
The compiler then goes on to moan about a not declared default constructor, because the static, as it assumes it to be, is default constructed. But even if you had a default constructor for X, it of course is still wrong because neither A is a static member of X, nor a static of X can be defined/declared at block scope.
You can make it not look like a declaration by doing several things. First, you can paren the whole expression, which makes it not look like a declaration anymore. Or just paren the type that is cast to. Both of these disambiguations have been mentioned in other answers:
(X(X::A)); (X)(X::A)
There is a similar, but distinct ambiguity when you try to actually declare an object. Look at this example:
int main() {
float a = 0;
int b(int(a)); // object or function?
}
Because int(a) can be both the declaration of a parameter called a and the explicit conversion (cast) of the float-variable to an int, the compiler decides again that that is a declaration. Thus, we happen to declare a function called b, which takes an integer argument and returns an integer. There are several possibilities how to disambiguate that, based on the disambiguation of above:
int b((int(a))); int b((int)a);
You should declare an object as
X x(X::A);
Bug in your code.
Either of these two lines work for me:
X obj(X::A);
X obj2 = X(X::A);
As Neil Butterworth points out, X(X::A) is being treated as a function declaration. If you really want an anonymous object, (X)(X::A) will construct an X object and immediately delete it.
You could, of course, just do something like this:
int main()
{
// code
{
X temp(X::A);
}
// more code
}
This would be more readable and basically have the same effect.