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

Ste*_*mer 6 c++ templates stl

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

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

我知道为了消除对成员函数模板的调用的歧义,我必须使用template关键字,我必须this在超类中明确引用.

this->base_member_obj.template member_function<int>();

所有这一切都很好,除了我正在使用的代码库导致导入整个的相当不幸的错误namespace std,并且我试图调用的模板成员函数被调用set.std::set包含在框架中的某个地方,这会导致GCC认为我正在尝试声明std::set而不是调用成员函数set.

GCC 4.7抛出错误无效使用'class std :: set'

请参阅下面的示例以显示错误.如果您注释掉using namespace std代码编译正常.

遗憾的是,我不可能通过整个代码库,删除每个using namespace 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;
}
Run Code Online (Sandbox Code Playgroud)

ink*_*boo 5

试试这个:

this->b.blah::template set<int>(); // this line breaks
Run Code Online (Sandbox Code Playgroud)

  • @lori:我会坚持使用`this-> b.blah :: template set <int>();`第二个可能是g ++中的一个怪癖,允许语法`Comeau`编译器以其非常严格的标准而闻名合规性. (2认同)

Pot*_*ter 3

嗯,这对于我们这些 C++ 推动者来说是相当尴尬的。

\n\n

这是 G++ 中的一个错误,在 Comeau Test Drive 中也出现过。这不是语言本身的缺陷。该问题源于解析的从左到右的本质以及 C++ 语法避免歧义的方式。

\n\n

在基类模板的 typedef 的嵌套名称说明符中使用非成员、非基类模板是合法的。在这种情况下,与访问的类没有特殊关系的类模板可以出现在->

\n\n
#include <tuple>\n\ntemplate< typename t >\nstruct get_holder\n    { typedef std::tuple< t > type; };\n\ntemplate< typename ... ts >\nstruct inherits\n    : get_holder< ts >::type ... {\n\n    inherits( ts ... v )\n        : get_holder< ts >::type( v ) ...\n        {}\n\n    template< typename tn >\n    void assign_one( inherits &o )\n        { this->get_holder< tn >::type::operator= ( o ); } // <- here!\n};\n\nint main() {\n    inherits< int, char, long > icl( 3, \'q\', 2e8 );\n    icl.assign_one< char >( icl );\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

由于 C++ 是从左到右解析的,因此当解析器命中 时->,它必须get_holder在继续之前进行解析。标准为此有一个特殊子句 \xc2\xa73.4.5/1 [basic.lookup.classref]:

\n\n
\n

在类成员访问表达式 (5.2.5) 中,如果 . 或 -> 标记后面紧跟一个标识符,后面跟一个 <,必须查找标识符以确定 < 是模板参数列表 (14.2) 的开头还是小于运算符。首先在对象表达式的类中查找标识符\n。如果未找到标识符,则在整个后缀表达式的上下文中查找该标识符并命名一个类模板。如果在对象表达式的类中查找\n 找到模板,则还会在整个后缀表达式的上下文中查找名称\n 并且

\n\n

\xe2\x80\x94 如果未找到名称,则使用在对象的类中找到的名称\n 表达式,否则

\n\n

\xe2\x80\x94 如果在整个后缀表达式的上下文中找到该名称并且未命名类模板,则使用在对象表达式的类中找到的名称\n,否则

\n\n

\xe2\x80\x94如果找到的名称是类模板,则它应引用与对象表达式的类中找到的实体相同的实体,否则程序格式错误。

\n
\n\n

强调我的 \xe2\x80\x94 看起来 G++ 遵循这个逻辑,尽管关键字出现在和 标识符template之间。此外,假设它沿着这条路线走,它应该将歧义标记为错误,而不是尝试选择非成员。.set

\n\n

标准中关于当关键字template出现如何继续的措辞似乎存在缺陷,但它不应该导致您看到的混乱。\xc2\xa714.2 [临时名称]:

\n\n
\n

当成员模板专业化的名称出现在 后时。或 -> 在后缀表达式中,或在限定 ID 中的嵌套名称说明符之后,并且后缀表达式或限定 ID 显式依赖于模板参数 (14.6.2) 但不引用当前实例化的成员 (14.6.2.1),成员模板名称必须以关键字 template 为前缀。否则,该名称将被假定为命名非模板。

\n
\n\n

我强调,该文本是错误的,应该显示为“假定该名称不是命名成员模板”,因为如上面的插图所示,它可能是嵌套名称说明符的一部分。如果文本按字面意思按原样理解,那么它可以被解释为意味着我的插图中需要template关键字,因此可以指示以下非成员模板(假设该语言完全支持这种构造),然后您的程序可能会被 G++ 所误解。

\n\n

但设计意图很明确,您不需要添加人为的嵌套名称说明符blah::,尽管这是一种合法的解决方法。

\n