我有一个继承自基类模板的类模板.
基类模板有一个带有成员函数模板的数据成员,我想从我的超类中调用它.
我知道为了消除对成员函数模板的调用的歧义,我必须使用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)
试试这个:
this->b.blah::template set<int>(); // this line breaks
Run Code Online (Sandbox Code Playgroud)
嗯,这对于我们这些 C++ 推动者来说是相当尴尬的。
这是 G++ 中的一个错误,在 Comeau Test Drive 中也出现过。这不是语言本身的缺陷。该问题源于解析的从左到右的本质以及 C++ 语法避免歧义的方式。
\n\n在基类模板的 typedef 的嵌套名称说明符中使用非成员、非基类模板是合法的。在这种情况下,与访问的类没有特殊关系的类模板可以出现在->:
#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}\nRun 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
强调我的 \xe2\x80\x94 看起来 G++ 遵循这个逻辑,尽管关键字出现在和 标识符template之间。此外,假设它沿着这条路线走,它应该将歧义标记为错误,而不是尝试选择非成员。.set
标准中关于当关键字template出现时如何继续的措辞似乎存在缺陷,但它不应该导致您看到的混乱。\xc2\xa714.2 [临时名称]:
\n\n\n当成员模板专业化的名称出现在 后时。或 -> 在后缀表达式中,或在限定 ID 中的嵌套名称说明符之后,并且后缀表达式或限定 ID 显式依赖于模板参数 (14.6.2) 但不引用当前实例化的成员 (14.6.2.1),成员模板名称必须以关键字 template 为前缀。否则,该名称将被假定为命名非模板。
\n
我强调,该文本是错误的,应该显示为“假定该名称不是命名成员模板”,因为如上面的插图所示,它可能是嵌套名称说明符的一部分。如果文本按字面意思按原样理解,那么它可以被解释为意味着我的插图中需要template关键字,因此可以指示以下非成员模板(假设该语言完全支持这种构造),然后您的程序可能会被 G++ 所误解。
但设计意图很明确,您不需要添加人为的嵌套名称说明符blah::,尽管这是一种合法的解决方法。
| 归档时间: |
|
| 查看次数: |
576 次 |
| 最近记录: |