Question

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.

Was it helpful?

Solution

X(X::A);

is being seen a s a function declaration. If you really want this code, use:

(X)(X::A);

OTHER TIPS

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));

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top