Most vexing parse

The most vexing parse is a specific form of syntactic ambiguity resolution in the C++ programming language. The term was used by Scott Meyers in Effective STL (2001).[1] It is formally defined in section 8.2 of the C++ language standard.[2]

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());

is seemingly ambiguous, since it could be interpreted either as

  1. a variable definition for variable time_keeper of class TimeKeeper, initialized with an anonymous instance of class Timer or
  2. a function declaration for a function time_keeper that returns an object of type TimeKeeper and has a single (unnamed) parameter that is a pointer to function returning an object of 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 (*)())’

Notice that the compiler gives the error message about the return statement of main(): since it interpreted the declaration of time_keeper as a function declaration we won't be able to call the member function get_time() on this.

Clang++ provides a warning:

$ clang++ time_keeper.cc
timekeeper.cc:14:25: warning: parentheses were disambiguated as a function declaration
      [-Wvexing-parse]
  TimeKeeper time_keeper(Timer());
                        ^~~~~~~~~
timekeeper.cc:14:26: note: add a pair of parentheses to declare a variable
  TimeKeeper time_keeper(Timer());
                         ^
                         (      )
timekeeper.cc:15:21: error: member reference base type 'TimeKeeper (Timer (*)())' is not a
      structure or union
  return time_keeper.get_time();
         ~~~~~~~~~~~^~~~~~~~~

The common ways to force the compiler to consider this as a variable definition are:

  • To add an extra pair of parentheses:
    TimeKeeper time_keeper((Timer()));
  • To use copy initialization:
    TimeKeeper time_keeper = TimeKeeper(Timer());
  • (In C++11 and later.) To use uniform initialization with braces:
    TimeKeeper time_keeper{Timer()};
    TimeKeeper time_keeper(Timer{});
    TimeKeeper time_keeper{Timer{}};

Example with functions

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:

// declares a variable called 'i'
int i((int) adouble);

Or also to use a named cast:

// declares a variable called 'i'
int i(static_cast<int>(adouble));

Uniform initialization syntax

Using the new uniform initialization syntax introduced in C++11 solves this issue.

The problematic code is then unambiguous when braces are used:

  TimeKeeper time_keeper{Timer{}};

Using braces as above creates a variable definition for variable time_keeper of class TimeKeeper, initialized with an anonymous instance of class Timer.

gollark: Binary search time!
gollark: I mean, most modern WiFi devices can use ~5GHz now too.
gollark: Or socially pressure/shame people into complying.
gollark: You can tell people to do or not do things, which has at least *some* influence on behavior.
gollark: OR CAN YOU?

References

  1. Meyers, Scott (2001). Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library. Addison-Wesley. ISBN 0-201-74962-9.
  2. ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §8.2 Ambiguity resolution [dcl.ambig.res]
This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.