Most vexing parse: Difference between revisions
i thought i fixed the formatting bug. hope now it's really fixed |
Fix g++ output, this is an error message copied verbatum, don't believe it, try to compile it yourself. |
||
Line 36: | Line 36: | ||
$ g++ -c time_keeper.cc |
$ g++ -c time_keeper.cc |
||
time_keeper.cc: In function ‘int main()’: |
time_keeper.cc: In function ‘int main()’: |
||
time_keeper.cc:15: error: request for member ‘get_time’ in ‘time_keeper’, which is of non-class type ‘TimeKeeper (Timer (*)())’ |
time_keeper.cc:15: error: request for member ‘get_time’ in ‘time_keeper’, which is of non-class type ‘TimeKeeper ()(Timer (*)())’ |
||
[[Clang++]] provides a useful warning: |
[[Clang++]] provides a useful warning: |
Revision as of 00:07, 3 October 2010
The most vexing parse is an extremely counterintuitive disambiguation of code in C++.
Example with classes
An example is:
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());
could be disambiguated either as
- a variable definition for variable time_keeper of class TimeKeeper, taking an anonymous instance of class Timer or
- a function declaration for a function time_keeper which returns an object of type TimeKeeper and takes a single (unnamed) argument 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.
For example, g++ gives the following error message:
$ g++ -c time_keeper.cc time_keeper.cc: In function ‘int main()’: time_keeper.cc:15: error: request for member ‘get_time’ in ‘time_keeper’, which is of non-class type ‘TimeKeeper ()(Timer (*)())’
Clang++ provides a useful warning:
$ clang++ time_keeper.cc time_keeper.cc:14:25: warning: parentheses were disambiguated as a function declarator TimeKeeper time_keeper(Timer()); ^~~~~~~~~
One way to force the compiler to consider this as a variable definition is to add an extra pair of parentheses:
TimeKeeper time_keeper( (Timer()) );
Simpler example
An even simpler example appears when a functional cast is intended to convert an expression for initializing a variable or passing to a constructor parameter
void f(double adouble) {
int i(int(adouble));
}
In this case, the parentheses around "adouble" are superfluous and the declaration of "i" is again a function declaration equivalent to the following
// takes an integer and returns an integer
int i(int adouble);
To disambiguate this in favour of a variable declaration, the same technique can be used as for the first case above. Another solution is to use the cast notation or to use a named cast
// declares a variable called 'i'
int i(static_cast<int>(adouble));
References
- Scott Meyers, "Effective STL", ISBN 0201749629
- http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=439
- http://blog.llvm.org/2010/04/amazing-feats-of-clang-error-recovery.html
- http://arstechnica.com/civis/viewtopic.php?f=20&t=767929