Why doesn't this enum convert to int? - c++

Why does the following code not compile under g++ (C++14), MSVC (C++14), or ARM (C++03)?
The named Error instance calls the integer constructor, but the anonymous Error instance does not resolve.
class Error
{
public:
Error(int err) : code_(err) {}
const int code_;
};
enum Value
{
value_1
};
int main()
{
// compiles
Error e(value_1);
// does not compile under G++, ARM, or MSVC
Error(value_1);
}
Example error under G++: (Coliru link)
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:19:18: error: no matching function for call to 'Error::Error()'
Error(value_1);
^
main.cpp:4:5: note: candidate: Error::Error(int)
Error(int err) : code_(err) {}
^~~~~
main.cpp:4:5: note: candidate expects 1 argument, 0 provided
main.cpp:1:7: note: candidate: constexpr Error::Error(const Error&)
class Error
^~~~~
main.cpp:1:7: note: candidate expects 1 argument, 0 provided
main.cpp:1:7: note: candidate: constexpr Error::Error(Error&&)
main.cpp:1:7: note: candidate expects 1 argument, 0 provided

This comes from the same place as "The Most Vexing Parse" - the rule that if it can be a declaration, it is a declaration.
And surprisingly, you're allowed to put parentheses around the identifier in a variable declaration.
(I have no idea why, but I'm guessing that it simplified C's parser back in the day.)
The following are all valid declarations of int variables:
int (foo);
int (bar) = 0;
int (baz)(3);
int (twaddle)(baz);

The problem is that code
Error(value_1);
is a declaration of a variable value_1 of type Error.
This is a legacy from C language that uses expressions as part of type declaration.
For example int *i is a pointer to int because it says that expression *i should evaluate to type int. More examples of this:
int (*func)() is a pointer to function returning int because expression (*func)() evaluates to type int.
int *p[8] is an array of pointers to int because expression *p[x] evaluates to type int.
int (*p)[8] is a pointer to array of 8 int's (int[8]) because expression (*p)[x] evaluates to type int.
int (*(*p[8])())() is an array of 8 pointers to functions returning pointers to a function returning int because expression (*(*p[x])())() evaluates to type int.
Similarly int (i) is a plain variable of type int as expression (i) evaluates to type int.
And so because C++ inherits this from C, it uses parenthesis as part of type declaration, but also adds more syntax on top, leading to some unexpected results.
The rule applied by C++ here says to treat everything that can be a declaration as a declaration.
Similar confusion if often caused by code like this:
Error ec();
which is a forward declaration of a function ec that returns Error.

main.cpp:19:18: error: no matching function for call to 'Error::Error()'
Error(value_1);
The compiler tries to call the non-existent default constructor Error::Error() because it sees
Error(value_1);
as a variable declaration
Error value_1;
A declaration is allowed to have redundant parenthesis.

Related

GCC and clang disagree on a parameter whose default value is a function with the same name as the parameter [duplicate]

I have a little toy program:
static int value = 0;
int function(int &value=value) {
return value;
}
int main() {
function();
}
Compiling with g++ 7.2:
g++ -std=c++11 -Wall -Wextra test.cc -o test
No problem.
Compiling with clang++-3.9:
clang++-3.9 -std=c++11 -Wall -Wextra test.cc -o test
test.cc:3:25: error: default argument references parameter 'value'
int function(int &value=value) {
^~~~~
test.cc:8:5: error: no matching function for call to 'function'
function();
^~~~~~~~
test.cc:3:5: note: candidate function not viable: requires single argument 'value', but no arguments were provided
int function(int &value=value) {
^
2 errors generated.
Kaboom. Who's right?
I think clang is correct. From basic.scope.pdecl:
The point of declaration for a name is immediately after its complete declarator (Clause [dcl.decl]) and before its initializer (if any), except as noted below. [ Example:
int x = 12;{ int x = x; }
Here the second x is initialized with its own (indeterminate) value. — end example ]
Also, from dcl.fct.default:
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 a default argument, even if they are not evaluated. Parameters of a function declared before a default argument are in scope and can hide namespace and class member names
Since the OP tagged the question as c++11 I checked that version of the standard and in [basic.lookup.unqual] sub-clause 11 it states explicitly that:
During the lookup for a name used as a default argument (8.3.6) in a
function parameter-declaration-clause or used in the expression of a
mem-initializer for a constructor (12.6.2), the function parameter
names are visible and hide the names of entities declared in the
block, class or namespace scopes containing the function declaration.
Thus, clang is correct.
Clang is correct here. First a function's parameter scope is defined as:
A function parameter (including one appearing in a lambda-declarator) or function-local predefined variable ([dcl.fct.def]) has function parameter scope. The potential scope of a parameter or function-local predefined variable begins at its point of declaration.[...]
and the point of declaration is defined as
The point of declaration for a name is immediately after its complete declarator and before its initializer (if any), except as noted below. [ Example:
unsigned char x = 12;
{ unsigned char x = x; }
Here the second x is initialized with its own (indeterminate) value. — end example ]
So value should be the value you just declared and not the one from the global space

What are the semantics of function as variable in C++

What are the semantics of declaring a function as a variable like this:
int main() {
int foo();
std::cout << foo; // prints 1
}
EDIT:
Why does this not cause a linker error?
If you look at this attempt to replicate your problem you will see a warning message from the compiler:
main.cpp:5:18: warning: the address of 'int foo()' will never be NULL [-Waddress]
A pointer to a function can never be a null pointer. But since all you have is a prototype, a declaration, and not any actual function definition the compiler evaluates it as "true".
Compile your program in C++ clang compiler and see the warning:
Warning(s):
source_file.cpp:5:12: warning: empty parentheses interpreted as a function declaration [-Wvexing-parse]
int foo();
^~
source_file.cpp:5:12: note: replace parentheses with an initializer to declare a variable
int foo();
^~
= 0
source_file.cpp:6:18: warning: address of function 'foo' will always evaluate to 'true' [-Wpointer-bool-conversion]
std::cout << foo; // prints 1
~~ ^~~
source_file.cpp:6:18: note: prefix with the address-of operator to silence this warning
std::cout << foo; // prints 1
^
&
2 warnings generated.
Why output 1?
Because according to warning address of function 'foo' will always evaluate to 'true'.

Calling class constructor with parameter - request of a member in 'x' which is of non-class type

I have a class A that accepts class B as a constructor parameter. Class B can be constructed from int value. My original code is quite complex, but I hope I've reduced it to the very base case:
class B {
public:
explicit B(int a) : val(a) {}
private:
int val;
};
class A {
public:
A(const B & val) : value(val) {};
void print() {
//does nothing
}
private:
B value;
};
int main() {
int someTimeVar = 22;
A a(B(someTimeVar));
a.print();
}
And this is the error code I'm getting:
$ g++ test.cpp -Wall -O0
test.cpp: In function ‘int main()’:
test.cpp:22:7: error: request for member ‘print’ in ‘a’, which is of non-class type ‘A(B)’
a.print();
^
test.cpp:20:9: warning: unused variable ‘someTimeVar’ [-Wunused-variable]
int someTimeVar = 22;
^
I use GCC (4.9.2 20150304 (prerelease)), platform: arch linux.
The following modification to the main function compiles fine:
int main() {
A a(B(22));
a.print();
}
I'm well aware that using A a(); declares a function, not a object. But I didn't expect that A a(B(some_val)) will do the same, and in my opinion this is what's happening here.
Do you have ideas why this is happening?
Edit: Thank you for all the answers, looks like I need to research more on most vexing parse idea.
BTW it turns out that compiling my code using clang provides more useful error message plus a solution:
$ clang test.cpp
test.cpp:21:8: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
A a(B(someTimeVar));
^~~~~~~~~~~~~~~~
test.cpp:21:9: note: add a pair of parentheses to declare a variable
A a(B(someTimeVar));
^
( )
test.cpp:22:6: error: member reference base type 'A (B)' is not a structure or union
a.print();
~^~~~~~
1 warning and 1 error generated.
A a(B(someTimeVar)) is interpreted as A a(B someTimeVar), so a is a function taking parameter of type B and returning A.
This is one of the reasons the uniform initialization was added to C++11:
A a{B{someTimeVar}};
This problem has its own tag here on stackoverflow. most-vexing-parse
Wikipedia har a clear description of the problem and its solution. https://en.wikipedia.org/wiki/Most_vexing_parse.
The line
TimeKeeper time_keeper(Timer());
could be disambiguated either as
a variable definition for variable time_keeper of class TimeKeeper, passed an anonymous instance of class Timer or
a function declaration for a function time_keeper which returns an object of type TimeKeeper and has a single (unnamed) parameter which
is a function returning type Timer (and taking no input). (See
Function object#In C and C++)
Most programmers expect the first, but the C++ standard requires it to
be interpreted as the second.
The solution is to add parenthesis to the argument like:
A a( (B(22)) );
or as others have noted use universal initialization like
A a { B{22} };
A a(B(someTimeVar)); declares a function with the return type A and one argument of type B named someTimeVar. It's the same as A a(B someTimeVar);
It works in A a(B(22)); because 22 is not a valid identifier, so the functio declaration would be invalid.
If your codebase uses C++11 (or newer), you can use uniform initialization with curly braces: A a(B{someTimeVar});

Global initialization with temporary function object

The following code
#include <random>
std::mt19937 generator((std::random_device())());
compiles just file with clang:
$ clang++ -c -std=c++0x test.cpp
but fails with gcc:
$ g++ -c -std=c++0x test.cpp
test.cpp:3:47: erro: expected primary-expression before ‘)’ token
Is that code valid in C++11? Is it a bug in GCC or a extension/bug of Clang?
gcc is parsing the subexpression (std::random_device())() as a cast to the function type std::random_device(). It helps to look at icc's error output, which is slightly more informative than gcc's:
source.cpp(6): error: cast to type "std::random_device ()" is not allowed
std::mt19937 generator((std::random_device())());
^
source.cpp(6): error: expected an expression
std::mt19937 generator((std::random_device())());
^
The relevant production is 5.4p2:
cast-expression:
unary-expression
( type-id ) cast-expression
Since an empty pair of parentheses () is not a unary-expression, this production is unavailable and the compiler should select the production from 5.2p1:
postfix-expression:
[...]
postfix-expression ( expression-listopt )
[...]
where the postfix-expression is (std::random_device()) and the expression-list is omitted.
I've filed http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56239 on gcc bugzilla, and it looks like it should be resolved shortly.
Note that if you are supplying arguments to the operator() then the compiler is required by 8.2p2 to parse the expression as a cast, even though it is illegal to cast to a function type (if there are multiple arguments, the argument list is parsed as an expression using the comma operator:
(std::less<int>())(1, 2);
^~~~~~~~~~~~~~~~~~ illegal C-style cast
^~~~~~~~~~~~~~~~ type-id of function type std::less<int>()
^~~~~~ argument of C-style cast
^ comma operator
The correct way to write this (other than using C++11 universal initializer syntax) is to add another layer of parentheses, since a type-id cannot contain outer parentheses:
((std::less<int>()))(1, 2);
Seems like there is problem with the way GCC handles function declarations. Take this example:
struct A
{
bool operator () () { return true; }
};
struct B
{
B(bool) { }
};
B b(( // This cannot be parsed as a function declaration,
A()() // and yet GCC 4.7.2 interprets it as such:
)); // "error: 'type name' declared as function returning
// a function B b((A()()));"
int main() { }
Due to the presence of additional parentheses around A()(), the syntactic form B b(( A()() )); cannot be parsed as a declaration of a function.
The declaration in your question's example is slightly different:
B b(
(A())()
);
Even in this case, though, (A())() cannot be interpreted as the type of a function which returns a function that returns A (always in an attempt to consider b as a function declaration with an unnamed parameter). So the question is: can it be interpreted as anything else? If so, and if its meaningful in this context, then the compiler should consider to parse the whole expression as the construction of object b.
This is probably the fundamental point where GCC and Clang disagree:
int main()
{
(A())(); // OK for Clang, ERROR for GCC
}
I do not see how the above could be interpreted as anything else than an attempt to construct a temporary of type A and invoke its call operator. It cannot be a function declaration, because if A is interpreted as the return type, then the name is missing (and vice versa).
On the other hand, (A()) is a valid expression for creating a temporary of type A, and that temporary supports the call operator (whose return type is the same as the type accepted by B's constructor). Thus, (A())() should be a valid expression of type bool.
For this reasons, I believe that GCC's parsing is wrong.

Explain GCC error after using an object accidentally declared as a function

The following is a common typo with language newcomers, who think that they are defining an object but are actually declaring a function:
struct T
{
void foo() {}
};
int main()
{
T obj();
obj.foo();
}
GCC 4.1.2's error is:
In function 'int main()':
Line 9: error: request for member 'foo' in 'obj', which is of non-class type 'T ()()'
compilation terminated due to -Wfatal-errors.
Why is the reported type in the message T ()()? I'd have expected T ().
IIRC this is just a compiler bug. GCC 4.4 says T() while 4.2 says T()() for me.
The error is best understood when you realize that you usually don't write out function types without naming at least the function, but it's a bit more common for function pointers.
For instance, int (*fooPtr)() names the pointer. If you omit the name, you have int (*)(). Now, going from function pointer to function type would give you int ()().
There's no real standard here, because ISO C++ doesn't define canonical names for all types. For instance, const volatile int is the same type as volatile const int, and neither form is canonical.