I have a class template which inherits from a base class template.
The base class template has a data member with a member function template which I want to call from within my super class.
I know that in order to disambiguate the call to the member function template, I have to use the template keyword, and I have to explicitly refer to this in the super class.
this->base_member_obj.template member_function<int>();
All this is good and well, except that the codebase I’m using has made the rather unfortunate mistake of importing the entirety of namespace std, and the template member function I’m trying to call is called set. Somewhere in the framework std::set is included, and this causes GCC to think I’m trying to declare a std::set rather than call the member function set.
GCC 4.7 throws an error invalid use of ‘class std::set’
See below for an example showing the error. If you comment out using namespace std the code compiles fine.
Sadly it is not feasible for me to go through the entire codebase, remove every using namespace std call, and prefix every call to anything inside the std namespace with std::
Is there any other way around this?
#include <set>
using namespace std; // comment this out to compile fine
struct blah
{
template<typename T>
void set()
{ }
};
template<typename T>
struct base
{
blah b;
};
template<typename T>
struct super : base<super<T>>
{
void fun()
{
this->b.template set<int>(); // this line breaks
}
};
int main()
{
super<int> s;
s.fun();
return 0;
}
Well, that’s rather embarrassing for us C++ pushers.This is a bug in G++, which also appears in Comeau Test Drive. It’s not a flaw in the language itself. The problem stems from the left-to-right nature of parsing and way C++ grammar skirts ambiguity.
It is legal to use a non-member, non-base class template in a nested name specifier to a typedef to a base class template. In such a context, a class template with no special relationship to the accessed class can appear after the
->:Since C++ is parsed left-to-right, when the parser hits the
->, it must resolveget_holderbefore proceeding. The Standard has a special clause §3.4.5/1 [basic.lookup.classref] for this:Emphasis mine — it would appear that G++ is following this logic despite the
templatekeyword appearing between the.and the identifierset. Furthermore, assuming it’s going down this route, it should have flagged the ambiguity as an error instead of trying to choose the non-member.There does appear to be a flaw in the standard’s wording of how to proceed when the
templatekeyword does appear, but it shouldn’t cause the mayhem you see. §14.2 [temp.names]:Emphasis mine, that text is in error and should read “the name is assumed not to name a member template,” because as in my illustration above it could be part of a nested name specifier. If the text is taken literally as-is, then it could be interpreted to mean the
templatekeyword is required in my illustration, hence could indicate a following non-member template (assuming the language supports such a construct at all), and then your program could be misinterpreted as seen by G++.But the design intent is clear, and you do not need to add an artificial nested name specifier
blah::, although it is a legal workaround.