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.
Related
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
I have:
int foo(int x) { return x+1; }
struct Bar {
decltype(foo) operator();
};
int main() {
Bar bar;
printf("%d\n",bar(6));
}
which results in the slightly startling compiler error message (g++ 4.6.1):
error: declaration of 'operator()' as non-function
When changing the member name to
decltype(foo) blubb;
and using it results in a linker error:
undefined reference to `Bar::blubb(int)'
Is this expected behaviour?
It seems that you want to "copy" the signature of another function to create a function with the same signature. Since decltype(foo) is indeed the type of the function (and not a pointer to that function, which would be decltype(&foo) and would lead to a pointer declaration), you can use it to declare a function with the same signature as another function.
As indicated by the linker error:
undefined reference to `Bar::blubb(int)'
this will already work fine with your compiler. However it seems that gcc did not yet fully implement this part of the standard, as it will not accept the syntax for the same thing with a function call operator. Clang btw. will happily accept it and the link then errors out with
undefined reference to `Bar::operator()(int)'
Your question about why that linker error exists indicates a misunderstanding of what decltype really does.
It will just evaluate to a type, not more. The definition of blubb is in no way tied to the definition of foo. This might be clearer when writing it like
typedef decltype(foo) x;
x blubb;
You can now alternatively typedef x to be explicitly the function type, which will not in any way change what blubb is. You still need to define it. And since there is no syntax to define it using decltype, you explicitly have to write it as
int Bar::operator()(int) {
...
}
which will likely and unfortunately defeat the purpose/benefit of using decltype for the declaration, as it will not allow you to automatically "copy" a signature.
This is a wild guess based on observing your usage of printf here:
printf("%d\n",bar(6));
This lets me assume you really want the return type of the function, not the type of the function. If so, then you use decltype wrong. You get the return type of the function by "simulating" the usage of the function, i.e.
decltype(foo(0)) operator() (int);
should be the right thing for you. Otherwise, if that was not your attention, you are skating on thin ice by giving a function type (and not function return type) to the %d specifier.
Generally, the meaning of decltype is: decltype(#) gives the static type of the expression #.
This should work.
I just used it here to capture whatever gobbledygook std::bind was going to give me:
class RiceFadingModel::Impl
{
public:
Impl(double K, double A)
: //...
_M_re{system_now()},
_M_rd{_M_nu, _M_sigma},
_M_gen{std::bind(_M_rd, _M_re)}
{ }
private:
//...
std::default_random_engine _M_re;
/// The underlying Rice distribution.
__gnu_cxx::__rice_distribution<double> _M_rd;
/// The variate generator built from the pseudo-random number engine and the Rice distribution.
decltype(std::bind(_M_rd, _M_re)) _M_gen;
};
This works like a charm on gcc-4.7. Now that I think about it I built it on mingw with gcc-4.5 too.
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.
The following C++ code does nothing (using GCC 4.4.3) - it does not print the text:
struct MyStruct { MyStruct() { cout << "Hello" << endl; } };
void foo() {
MyStruct ();
}
I think this is not so obvious... Let alone the danger of forgetting to give a variable name. Is there a compiler option/warning to forbid compilation of such code or is there any hidden secret behind allowing it?
Edit: I am sorry. The version above MyStruct(); acutally prints. The version which is not printing is:
void bar() {
MyStruct a();
}
So now I am a bit confused.
This is not a declaration, because in MyStruct ();, the MyStruct would be part of the decl-specifier-seq and forms a type-name therein. And then () can only be a function-declarator. This requires that there is a declarator-id specified, which in your case is not. A special syntactical form is needed to allow such a syntax in declaring a constructor. But such syntactical exceptions are not made in a declaration-statement.
So this construct cannot be a declaration. It is parsed as an expression which specifies a functional cast creating a temporary of type MyStruct.
If the compiler does not print Hello it is either non-conforming or you are not calling foo in your program.
Your edit also does not specify a declaration without a name. It instead specifies a declaration that does have a name. It declares a function that is called a. The compiler has no way that you meant something else by this.
MyStruct a();
It could in an effort deduce this by having a recovering rule when it later discovers errors in your code such as the following
a.f();
If you have this in your code to try and call a member function and "a" is a function, the compiler could check to see if MyStruct contains a member f such that this expression is well-formed. But what if you just forgot to place parentheses? The following would be valid for the above declared function that returns a MyStruct, assuming a suitably declared member f.
a().f();
So in effect, the compiler can't really know what you mean.
You don't have "a declaration with no name" in your code. You have a completely valid expression MyStruct(). It is not a declaration, once again, it is an expression statement. If it doesn't print anything, it mist be the effect of optimization: in C++ it is generally allowed to eliminate temporaries, even if their constructors/destructors have side effects. (Although this context is not really one where such elimination is allowed. Are you sure you actually execute that expression statement?)
MyStruct a(); declares a function a that takes no arguments and returns a MyStruct.
I think the temporary is elided [due to compiler optimization], hence you don't see the call to the c-tor.
Your code is syntactically perfect so there is no need for the compiler to give a warning [as such].
EDIT [As per the edits in the OP]
MyStruct a();
The above is parsed as the declaration of a function a return a MyStruct object and taking no parameters.
Well, temporary objects are perfectly legals. So there is no reasons to warn here.
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>());