我有一个继承自基类模板的类模板。
基类模板有一个带有成员函数模板的数据成员,我想从我的超类中调用它。
我知道为了消除对成员函数模板的调用的歧义,我必须使用template
关键字,我必须在超类中明确引用this
。
this->base_member_obj.template member_function<int>();
所有这一切都很好,除了我使用的代码库导致导入整个namespace std
的相当不幸的错误,我试图调用的模板成员函数被称为{{ 1}}。包含框架set
中的某个地方,这会导致GCC认为我正在尝试声明std::set
而不是调用成员函数std::set
。
GCC 4.7引发错误无效使用'class std :: set'
请参阅下文,了解显示错误的示例。如果您注释掉set
,则代码编译得很好。
遗憾的是,我不可能通过整个代码库,删除每个using namespace std
调用,并使用using namespace std
还有其他方法吗?
std::
答案 0 :(得分:5)
试试这个:
this->b.blah::template set<int>(); // this line breaks
答案 1 :(得分:3)
嗯,这对我们C ++的推动者来说相当尴尬。
这是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]:
在类成员访问表达式(5.2.5)中,如果是。或 - &gt;令牌是 紧接着是一个标识符,后跟一个&lt ;, 标识符 必须抬头确定是否&lt;是一个开始 模板参数列表(14.2)或小于运算符。标识符 首先在对象表达式的类中查找。如果 找不到标识符,然后在上下文中查找 整个postfix-expression并命名一个类模板。如果 在对象表达式的类中查找找到一个模板, name也在整个postfix-expression的上下文中查找 和
- 如果找不到名称,则在对象的类中找到该名称 使用表达式,否则
- 如果在整个postfix-expression的上下文中找到该名称 并且没有命名类模板,在类的类中找到的名称 使用对象表达式,否则
- 如果找到的名称是类模板,则应引用相同的名称 实体作为在对象表达式的类中找到的实体, 否则该计划格式不正确。
强调我的 - 尽管template
和标识符.
之间出现了set
关键字,但G ++似乎遵循了这一逻辑。此外,假设它沿着这条路线走下去,它应该将歧义标记为错误,而不是试图选择非成员。
当template
关键字 出现时,标准中有关如何处理的措辞似乎存在缺陷,但它不会导致您看到的混乱。 §14.2[temp.names]:
当成员模板专业化的名称出现之后。或 - &gt;在postfix-expression中,或在qualified-id中的nested-name-specifier之后,postfix-expression或qualified-id显式依赖于template-parameter(14.6.2)但不引用成员当前实例化(14.6.2.1),成员模板名称必须以关键字模板为前缀。 否则,假定该名称为非模板命名。
强调我的,该文本是错误的,应该读作“假定名称不是为了命名成员模板”,因为如上图所示它可能是嵌套名称说明符的一部分。如果文本字面上按原样,那么它可以被解释为在我的插图中需要template
关键字 ,因此可以指示以下非成员模板(假设语言完全支持这样的构造),然后你的程序可能会被G ++看错误解释。
但设计意图很明确,您不需要添加人工嵌套名称说明符blah::
,尽管这是一种合法的解决方法。
答案 2 :(得分:3)
您有两种选择:
this->b.blah::template set<int>();
// ^^^^^^ Be very explicit what set you want
或者,不要使用using namespace
(最佳选择)。