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'.
Related
My question is similar to this answered question, but with one big difference.
If I try to compile the following,
void test(string x){
int x = 5;
cout << x << endl;
}
I get the expected warning:
In function ‘void test(std::__cxx11::string)’:
error: declaration of ‘int x’ shadows a parameter
int x = 5;
^
Now to get to the meat of my question; if I have a type with a function call operator like the following:
struct foo{
string bar;
foo(const string& bar) : bar(bar) { }
void operator()(){
cout << "my bar is \"" << bar << '"' << endl;
}
};
I can create a temporary object and call its () operator with foo("this will print")(); or with foo{"this will also print"}();
If I try to do the following, I will get a compiler error which is expected and can be explained with the post I linked above.
void redeclaration_error(){
string x("lol");
foo(x)();
}
However, things get weird here:
void hmm1(string str){
foo(str)();
}
void hmm2(string str){
foo{str}();
}
While hmm2 will print out its argument when called, hmm1 will do absolutely nothing. This is expected, as hmm1's body does nothing more than declare str to be of type foo. However, in the scope of hmm1, str is already declared as type string from the function's parameter, so why does this not result in a compiler error like error: declaration of ‘foo str‘ shadows a parameter?
I understand that the compiler is interpreting foo(str)(); as a declaration, and that lines like foo(str).operator()(); and (foo(str))(); will be interpreted as creating a temporary foo object and calling their function call operator, but why it it okay to declare a variable with the same name as a parameter in this circumstance?
Here's and Ideone link where I was playing around with this.
A simpler program to produce the same issue (the extra parentheses are a red herring):
void f(int x)
{
void x();
}
This is incorrect because of C++17 [basic.scope.block]/2:
[...] A parameter name shall not be redeclared in the outermost block of the function
definition nor in the outermost block of any handler associated with a function-try-block.
If a compiler accepts this code then it is a compiler bug.
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.
I tried to write a void function with a return type and for some reason that works fine.
Here is the some code I tried to compile:
void a(){
return b();
}
void b()
{
printf("%s","void:)");
}
And the next code also works correctly:
int main()
{
a();
return 0;
}
void a(){
return 5;
}
Which of the above is correct according to the standard?
Second, why does it compile?
Which of the above is correct according to the standard?
Neither is correct according to C and C++ standard. C standard says that:
6.8.6.4 The return statement:
A return statement with an expression shall not appear in a function whose return type
is void. A return statement without an expression shall only appear in a function
whose return type is void.
Also read this answer for more detailed explanation.
Second, why does it compile?
Compilation doesn't guarantee that your code can't produce errors. It can. Better to compile your code with maximum warning flags. I compiled the second code with following options and got the following warnings:
In function 'main':
[Warning] implicit declaration of function 'a' [-Wimplicit-function-declaration]
At top level:
[Warning] conflicting types for 'a' [enabled by default]
[Note] previous implicit declaration of 'a' was here
In function 'a':
[Warning] 'return' with a value, in function returning void [enabled by default]
Although code compiled but there are some errors and violation of C standard.
Both programs are invalid. You failed to provide a function definition or declaration of b() in the first program before calling it in a(), and you failed to provide a function definition of a() before calling it in main() in the second program.
Your compiler is providing a "default" prototype for an undeclared function:
int func();
which is a function taking any arguments and returning int. This is probably not what you want. Your compiler should have issued a warning saying that it was supplying a default function declaration.
If you forward-declare the functions correctly (void b(); and void a();), the compiler will correctly reject both programs.
I was looking at some code a friend sent me, and he said: "It compiles, but doesn't work". I saw that he used the functions without the parentheses, something like this:
void foo(){
cout<< "Hello world\n";
}
int main(){
foo; //function without parentheses
return 0;
}
The first I said was "use parentheses, you have to". And then I tested that code - it does compile, but when executed doesn't work (no "Hello world" shown).
So, why does it compile (no warning at all from the compiler GCC 4.7), but doesn't work?
It surely warns if you set the warning level high enough.
A function name evaluates to the address of the function, and is a legal expression. Usually it is saved in a function pointer,
void (*fptr)() = foo;
but that is not required.
You need to increase the warning level that you use. foo; is a valid expression statement (the name of a function converts to a pointer to the named function) but it has no effect.
I usually use -std=c++98 -Wall -Wextra -pedantic which gives:
<stdin>: In function 'void foo()':
<stdin>:2: error: 'cout' was not declared in this scope
<stdin>: In function 'int main()':
<stdin>:6: warning: statement is a reference, not call, to function 'foo'
<stdin>:6: warning: statement has no effect
foo;
You're not actually 'using' the function here. You're just using the address of it. In this case, you're taking it but not really using it.
Addresses of functions (i.e. their names, without any parenthesis) are useful when you want to pass that function as a callback to some other function.
Trying to compile:
class AnonymousClass
{
public:
AnonymousClass(int x)
{
}
};
int main()
{
int x;
AnonymousClass(x);
return 0;
}
generates errors from MSVC:
foo.cpp(13) : error C2371: 'x' : redefinition; different basic types
foo.cpp(12) : see declaration of 'x'
foo.cpp(13) : error C2512: 'AnonymousClass' : no appropriate default constructor available
g++'s error messages are similar:
foo.cpp: In function ‘int main()’:
foo.cpp:13: error: conflicting declaration ‘AnonymousClass x’
foo.cpp:12: error: ‘x’ has a previous declaration as ‘int x’
foo.cpp:12: warning: unused variable ‘x’
It's easily fixable by giving the AnonymousClass object an explicit name, but what's going on here and why? I presume that this is more declaration syntax weirdness (like the cases described in Q10.2 and Q10.21 of the comp.lang.C++ FAQ), but I'm not familiar with this one.
AnonymousClass(x);
It defines a variable x of type AnonymousClass. That is why you're getting redefinition error, because x is already declared as int.
The parentheses are superfluous. You can add even more braces like:
AnonymousClass(x);
AnonymousClass((x));
AnonymousClass(((x)));
AnonymousClass((((x))));
//and so on
All of them are same as:
AnonymousClass x;
Demo: http://www.ideone.com/QnRKH
You can use the syntax A(x) to create anonymous object, especially when calling a function:
int x = 10;
f(A(x)); //1 - () is needed
f(A((((x))))); //2 - extra () are superfluous
Both line 1 and 2 call a function f passing an object of type A :
http://www.ideone.com/ofbpR
But again, the extra parentheses are still superfluous at line 2.
You're missing an actual name for your variable/object:
AnonymousClass myclass(x);
Instead of that you could as well write...
AnonymousClass (myclass)(x);
So your line of code results in this:
AnonymousClass (x);
Or more common:
AnonymousClass x;
Why it happens? Brackets are just there for logical grouping ("what belongs together?"). The only difference is, they're forced for arguments (i.e. you can't just write AnonymousClass myclass x).
To avoid such a mistake, just remember one rule: If you declare an anonymous object with one argument, just place it into a pair of parentheses!