Is the Most Vexing Parse rooted in the ambiguity about whether or not to use void
as the parameter of a function declaration that takes no arguments?
As an example, the following code compiles without error, and runs fine, on both the g++ (v7.2.1) and Xcode (Apple LLVM version 7.0.2 (clang-700.1.81)) compilers.
#include <iostream>
int asdf(void);
int asdf(int a) {
return a;
}
int main() {
std::cout << asdf(6) << std::endl; //-> 6
return 0;
}
This goes all the way back to the ANSI-C standard and before, where an empty parameter list indicated an arbitrary number of arguments. It haunts us today with backward-compatibility in the compilers, that seem to be a bit confused about the issue. Should the above not at least generate a warning, if not throw an error?
Here I had an epiphany (or perhaps a pipe dream!). Could it be that The Most Vexing Parse is rooted in the ambiguity about the use of void
in an empty function declaration list?
Another example, Referencing the following Wikipedia example:
class Timer {
public:
Timer();
};
class TimeKeeper {
public:
TimeKeeper(const Timer& t);
int get_time();
};
int main() {
TimeKeeper time_keeper(Timer());
return time_keeper.get_time();
}
The line
TimeKeeper time_keeper(Timer());
is seemingly ambiguous, since it could be interpreted either as
- a variable definition for variable time_keeper of class TimeKeeper, initialized with 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 pointer to function returning type Timer (and taking no input). (See Function object#In C and C++)
REFERENCE: https://en.wikipedia.org/wiki/Most_vexing_parse
Now, if we specify that void
must be used when declaring a function with no variables, does this not remove (not hackishly, fundamentally remove!) the ambiguity? The line in question would then become the following, leaving no doubt that it is a function declaration:
int main() {
TimeKeeper time_keeper(Timer(void));
return time_keeper.get_time();
}
This goes all the way back to KnR, where this issue is discussed:
Since the specialized versions of getline and copy have no arguments, logic would suggest that their prototypes at the beginning of the file should be
getline()
andcopy()
. But for compatibility with older C programs the standard takes an empty list as an old-style declaration, and turns off all argument list checking; the wordvoid
must be used for an explicitly empty list. [Kernighan & Richie, the C programming language, 1988, Pgs 32-33]
and..
The special meaning of the empty argument list is intended to permit older C programs to compile with new compilers. But it's a bad idea to use it with new programs. If the function takes arguments, declare them; if it takes no arguments, use void [ibid, Pg. 73]
Reference: is f(void) deprecated in modern C and C++
A function definition is also a declaration. That means when you have
You have declared two version of
asdf
, one taking anint
and one taking nothing. You then go on to use theint
version when you useThere is nothing wrong with that since the
int
version is defined.What would be an issue would be if you try to use
When you do that since it has be declared but not defined you should get an
Since there is no definition. This has nothing to do with the most vexing parse but just the difference between function declarations and definitions.
Your proposal would not completely remove the ambiguity.
Consider:
This looks like it could be declaring a local variable
bar
of typeFoo
, passing astd::string
to its constructor.But what it actually means is:
I.e. declare
bar
as a function taking an argument of type "pointer tostd::string
" and returning aFoo
.This example can't be fixed by adding
void
.