Consider the following code:
#include <iostream>
using f = void(std::string);
void fcorrect(f func, std::string s) {
func(s); // calling function
};
void fmistake(f func, std::string s) {
f(s); // calling type alias instead of function
};
void myprint(std::string s) {
std::cout << s << std::endl;
};
int main() {
std::string s = "message";
fcorrect(myprint, s);
fmistake(myprint, s);
return 0;
}
Function fcorrect
receives myprint
function and a string as arguments and prints this string as expected.
Function fmistake
contains a deliberate mistake - it calls type alias f
instead of function func
. It prints nothing.
I wonder what's happening under the hood when the latter function call takes place? Namely, why no compile time or runtime error are thrown?
As stated by commenters, f(s)
is a declaration. The crucial wording is here:
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a
(
. In those cases the statement is considered a declaration, except as specified below.[ Example 2:
class T { /* [...] */ }; // [...] T(a); // declaration // [...]
-- end example ]
It doesn't matter what the type is (class, function, etc.), T(a)
is a declaration if T
names a type.
The declaration f(s)
does nothing here because it is not used, and is equivalent to f s
or void s(std::string)
. s
is already a function parameter std::string s
in this context, so GCC is wrong about allowing it. GCC also allows:
void fmistake(f func, std::string s) {
void s(std::string);
}
// GCC also allows the following (in C++ mode)
void foo(int x) {
// GCC rejects this as re-declaring a symbol in C, but not in C++ mode.
void x(int);
}
This is a known GCC bug 52953, and has first been reported in 2012.