4

I've got the following code:

enum nums {
  a
};

class cls {
public:
  cls( nums );
};

void function()
{
  cls( a );
}

When I try to compile it with gcc, I get the following error:

test.cpp: In function ‘void function()’:
test.cpp:12:10: error: no matching function for call to ‘cls::cls()’
test.cpp:12:10: note: candidates are:
test.cpp:7:3: note: cls::cls(nums)
test.cpp:7:3: note:   candidate expects 1 argument, 0 provided
test.cpp:5:7: note: cls::cls(const cls&)
test.cpp:5:7: note:   candidate expects 1 argument, 0 provided
make: *** [test] Error 1

If I replace the function with this:

void function()
{
  cls name( a );
}

then everything works. It also works if I use a constructor with two arguments. It does not work if I add "explicit" to the constructor.

I get that gcc is somehow parsing this as defining a variable of type "cls" with the name "a", but I am not familiar with such a syntax for defining variables. To my eyes, this is a statement defining an anonymous temporary variable of type cls, passing "a" is the parameter.

Compiled with gcc 4.6.3.

Any insights?

Thanks, Shachar

NREZ
  • 942
  • 9
  • 13
Shachar Shemesh
  • 8,193
  • 6
  • 25
  • 57

2 Answers2

10

Another example of the most embarassing parse problem. The line:

cls( a );

declares a local variable named a of type cls, which is (or should be) initialized by calling the default constructor. Which doesn't exist, whence the error message.

If you really want to construct a temporary object which will be destructed immediately after, you can remove the ambiguity by putting the entire expression in parentheses:

(cls( a ));

A definition cannot occur in parentheses; an expression can.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
8

The parentheses are optional. So cls (a); is the same as cls a;, which declares an object a of type cls and default-initializes it (which fails because there is no matching constructor).

To just create a temporary value that expires at the end of the expression, you can say cls { a }; in C++11, or (cls(a)); (or any number of more arcane constructs, like void(0), cls(a);).

See this answer for more ideas.

Community
  • 1
  • 1
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • That resembles "most vexing parse" – gx_ Jul 11 '13 at 13:06
  • @gx_: Both the MVP and the OP's problem are based on statements being function declarations rather than expression-statements if there's an ambiguity. – Kerrek SB Jul 11 '13 at 13:08
  • What is the use of those parentheses? – johnchen902 Jul 11 '13 at 13:10
  • @johnchen902: The parenthesized statement can only be interpreted in one way (namely as an expression). – Kerrek SB Jul 11 '13 at 13:11
  • @KerrekSB I meant the parentheses in `cls (a);`. – johnchen902 Jul 11 '13 at 13:12
  • @KerrekSB: but it is not interpreted as an expression. It is interpreted as a variable definition – Shachar Shemesh Jul 11 '13 at 13:12
  • @johnchen902: Oh. Those are optional. Like in `cls((((a))))`. – Kerrek SB Jul 11 '13 at 13:14
  • @KerrekSB "(...) statements being _declarations_ rather than expression-statements if there's an ambiguity", not always _function_ declarations; that's why I said "resembles", because the "typical" MVP implies an unwanted function declaration and this question implies an unwanted _variable_ declaration. (So my comment was not a criticism, just a comment :)) – gx_ Jul 11 '13 at 13:17
  • @KerrekSB Is there a direct reason that those parentheses are *allowed*? – johnchen902 Jul 11 '13 at 13:17
  • 2
    @johnchen902: You sometimes *have* to be able to group type name parts explicitly, so this is a generally useful feature, like in `(int *)[10]`, as opposed to `int * [10]`. – Kerrek SB Jul 11 '13 at 13:18
  • 1
    @KerrekSB Rather `int (*p)[10]` (ptr-to-array) vs `int* a[10]` (array of ptrs) ("`(int *)[10]`" is not valid syntax) – gx_ Jul 11 '13 at 13:22
  • @gx_: Perhaps a more immediate example: `new int (*)[10]` is not valid syntax, but `new (int (*)[10])` is. – Kerrek SB Jul 11 '13 at 13:42