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;
}
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
.