基类模板有一个带有成员函数模板的数据成员,我想从我的超类中调用它.
我知道为了消除对成员函数模板的调用的歧义,我必须使用template关键字,我必须在超类中明确地引用它.
this-> base_member_obj.template member_function< int>();
所有这一切都很好,除了我正在使用的代码库导致了导入整个命名空间std的相当不幸的错误,而我试图调用的模板成员函数被称为set.框架中的某个地方包含了std :: set,这导致GCC认为我正在尝试声明一个std :: set而不是调用成员函数集.
GCC 4.7抛出错误无效使用’class std :: set’
请参阅下面的示例以显示错误.如果您使用命名空间std注释掉代码编译正常.
遗憾的是,我不可能遍历整个代码库,删除每个使用的命名空间std调用,并使用std ::为std命名空间内的任何内容添加前缀.
还有其他方法吗?
#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; }
解决方法
这是G中的一个错误,也出现在Comeau Test Drive中.这不是语言本身的缺陷.问题源于解析的左右性质以及C语法模糊的方式.
将嵌套名称说明符中的非成员非基类模板用于基类模板的typedef是合法的.在这样的上下文中,在>之后可以出现与所访问的类没有特殊关系的类模板.
#include <tuple> template< typename t > struct get_holder { typedef std::tuple< t > type; }; template< typename ... ts > struct inherits : get_holder< ts >::type ... { inherits( ts ... v ) : get_holder< ts >::type( v ) ... {} template< typename tn > void assign_one( inherits &o ) { this->get_holder< tn >::type::operator= ( o ); } // <- here! }; int main() { inherits< int,char,long > icl( 3,'q',2e8 ); icl.assign_one< char >( icl ); }
由于C从左到右解析,当解析器命中 – >时,它必须在继续之前解析get_holder.标准有一个特殊条款§3.4.5/ 1 [basic.lookup.classref]:
In a class member access expression (5.2.5),if the . or -> token is
immediately followed by an identifier followed by a <, the identifier
must be looked up to determine whether the < is the beginning of a
template argument list (14.2) or a less-than operator. The identifier
is first looked up in the class of the object expression. If the
identifier is not found,it is then looked up in the context of the
entire postfix-expression and shall name a class template. If the
lookup in the class of the object expression finds a template,the
name is also looked up in the context of the entire postfix-expression
and— if the name is not found,the name found in the class of the object
expression is used,otherwise— if the name is found in the context of the entire postfix-expression
and does not name a class template,the name found in the class of the
object expression is used,otherwise— if the name found is a class template,it shall refer to the same
entity as the one found in the class of the object expression,
otherwise the program is ill-formed.
强调我的 – 尽管模板之间出现了模板关键字,但G似乎遵循了这个逻辑.和标识符集.此外,假设它正沿着这条路线走下去,它应该将歧义标记为错误,而不是试图选择非成员.
当模板关键字出现时,标准的措辞似乎存在缺陷,但它不应该引起您看到的混乱. §14.2[temp.names]:
When the name of a member template specialization appears after . or -> in a postfix-expression,or after a nested-name-specifier in a qualified-id,and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2) but does not refer to a member of the current instantiation (14.6.2.1),the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
强调我的,该文本是错误的,应该读作“假定名称不是为成员模板命名”,因为如上图所示,它可能是嵌套名称说明符的一部分.如果文本字面上按原样,那么它可以被解释为在我的插图中需要模板关键字,因此可以指示以下非成员模板(假设语言完全支持这样的构造),然后你的如G所见,程序可能会被误解.