无效的模板依赖成员函数模板推导 - 认为我正在尝试使用std :: set

时间:2012-05-03 06:46:34

标签: c++ templates stl

我有一个继承自基类模板的类模板。

基类模板有一个带有成员函数模板的数据成员,我想从我的超类中调用它。

我知道为了消除对成员函数模板的调用的歧义,我必须使用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命名空间内的任何内容添加前缀。

还有其他方法吗?

std::

3 个答案:

答案 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(最佳选择)。