Search code examples
c++most-vexing-parse

(Why) is this instantiation of a template class with a temporary/anonymous object a vexing parse?


This code:

// main.cpp

template< typename T >
class Owner {
public:
  Owner( const T& t )
    : t_( t ) {}

  void func() { }

private:
  T t_;
};

class Foo {
};

int main( int argc, char* argv[] ) {
  Owner<Foo> owner( Foo() );

  owner.func();

  return 0;
}

generates this error:

$ g++ --version && g++ -g ./main.cpp
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

./main.cpp: In function ‘int main(int, char**)’:
./main.cpp:22:9: error: request for member ‘func’ in ‘owner’, which is of non-class type ‘Owner<Foo>(Foo (*)())’
   owner.func();
         ^~~~

Question: Is this a compile error because the definition of owner is a vexing parse, and if so, why?
I'm trying to tease apart how the compiler might interpret the definition of owner as anything other than a variable declaration...I can see how it might think "owner is a function that returns an instance of Owner<Foo>" but I don't see why that wouldn't be ruled out by the temporary/anonymous variable in the parentheses - how could that be confused with an argument list?

Question: Is there a workaround that allows me to instantiate a Owner<Foo> instance with a temporary/anonymous variable? I.e. instantiating a Owner<Foo> with a temporary named Foo instance works around this compiler problem, but I'd like to avoid that. I.e. the following works, but I'd like to avoid creating named Foo instances:

// main.cpp

template< typename T >
class Owner {
public:
  Owner( const T& t )
    : t_( t ) {}

  void func() { }

private:
  T t_;
};

class Foo {
};

int main( int argc, char* argv[] ) {
  Foo tmp;
  Owner<Foo> owner( tmp );

  owner.func();

  return 0;
}

Solution

  • This declaration:

    Owner<Foo> owner( Foo() );
    

    is indeed a vexing parse. It declares owner as a function that returns an Owner<Foo>, and which has a single parameter. That single parameter Foo() is itself interpreted as a function that returns a Foo and has no parameters.

    The simplest way to fix this is by using braces instead of parentheses:

    Owner<Foo> owner{ Foo{} };
    

    and now there's no ambiguity, and no need for any named variables of type Foo.