I\'m trying to compile with g++ some code previously developed under Visual C++ 2008 Express Edition, and it looks like g++ won\'t let me call a template m
could you try with?
template<typename T>
int do_outer(T& val)
{
return val.get_inner().template get<int>();
}
I don't have access to gcc atm, but I've had similar issues and adding the template keyword always solved them. And it works in VS too.
Just to give some background on why the template
keyword is needed:
template<typename T>
int do_outer(T& val)
{
int i;
val.get_inner().get<int>(i);
return i;
}
When the compiler sees this function, it does not know what the type of val
is. It therefore parses the line val.get_inner().get(i)
as follows:
1: val .
The compiler sees the .
and so can assume that 'val' has class type and the next identifier is the name of a member object or function.
2. val . get_inner (
get_inner
is the name of the member and then the compiler sees the (
. The only possibility is that get_inner
is a function name and so this is a function call. It then parses the parameters until it finds the closing )
.
3. val . get_inner () .
As for the first step, it now knows that the return from get_inner must be a class type so it knows that the next identifier is a member object or function.
4. val . get_inner () . get <
So, what can the <
possibly mean? Of course it's the start of template arguments...or maybe it's the less than operator?
We know that get
can only be an object or a function. If it is an object then the <
makes perfect sense as the less than operator. Furthermore, the standard more or less states that only where the name before the <
is a template-name
will it treat the <
as template arguments (14.2/3):
After name lookup (3.4) finds that a name is a template-name, if this name is followed by a
<
, the<
is always taken as the beginning of a template-argument-list and never as a name followed by the less-than operator.
In this case, the compiler has no idea what the type of the expression val.get_inner()
is and so it cannot lookup get
. It more or less assumes then that it's a member object and not a template-name. '<' is treated as the less than operator and the compiler ends up checking if get
is less than int
- hence the error.
So, why do the fixes work?
Adding the template
keyword
Literally we're telling the compiler that the get
is a template-name and so the <
operator is treated as the start of a template argument list.
Removing the template-arguments
When do_outer doesn't have the template arguments ie: val . get_inner () . get (
the compiler expects that the member get
is an object or a function. The (
disambiguates between these two and the name is treated as a function. Later template argument deduction then works out the type of the template parameter.
I can't claim to be one of the, oh 10 people on the planet who fully understand C++ templates, but what you're doing here looks fine to me. (It fails with GCC 4.4.1 with the same error, BTW).
Changing do_outer
to
const Inner& inner = val.get_inner();
return inner.get<int>();
works with GCC and presumably will also work with Visual C++.
You might consider filing a bug with GCC; either they'll fix it, or it will be closed as INVALID and in the process someone will hopefully explain why what you're doing is not valid code.
A further update and AHA: It turns out it's not actually valid code, GCC just gives a horrible error message. Intel C++ outputs the (actually helpful!) error message:
template.cpp(24): error: type name is not allowed
return val.get_inner().get<int>();
Which made me realize the problem. Changing do_inner to
return val.get_inner().template get<int>();
the code is accepted by both ICC and GCC.