我们是否需要在嵌套类型的成员参数前面加上"::"?
Do we need to prefix member arguments of nested type with "::"?
例如,考虑以下名称nest1
冲突的情况:
template <typename U> class nest1 {};
class cls {
public:
template <typename V> class nest1 {};
template <typename W> class nest2 {
public:
void bar(nest1<W> x);
};
};
template <typename W>
void cls::nest2<W>::bar(nest1<W> x) {} // how does compiler know which nest<1>?
- 编译器如何知道
bar
是否需要nest1<W>
或cls::nest1<W>
,如果我们不前缀cls::
(例如bar(cls::nest1<W> x)
)? - 明确前缀
cls::
是好做法吗?
注意:编译器实际上隐式地选择声明 bar(cls::nest1<W> x)
:
- 呼叫
cls::nest1<W> x; bar(x);
works: http://ideone.com/3ZuH2Z - 通过
nest1<W> x; bar(x);
失败:http://ideone.com/6HmA3f
在成员函数名之后使用的每个名称也在其类的词法作用域中查找。这导致了以下(看似)不一致的行为,因为在类的词法作用域中,正常的返回类型是而不是:
struct X{
struct Y{};
Y foo(Y);
Y bar(Y);
};
// normal return type is before 'foo', needs explicit scope qualification
// parameter doesn't (after 'foo')
X::Y X::foo(Y y){ return y; }
// trailing-return-type also doesn't (after 'bar')
auto X::bar(Y y) -> Y{ return y; }
关于这个的标准,我们看§9.3 [class.mfct] p5
:
如果成员函数的定义在词法上超出其类定义,则成员函数的名称应使用
::
操作符由其类名限定。[注意:在成员函数定义(即在形参声明子句包括默认实参(8.3.6)或在成员函数体中)中使用的名称按3.4中描述的方式查找。 -end note][…]
然后在§3.4.1 [basic.lookup.unqual] p8
处(非限定名称查找,例如没有::
):
在类
X
的成员函数(9.3)的定义中使用的名称,在函数的声明符id31[…]]应以下列方式之一声明:
- […]
- 应是
X
类的成员或X
(10.2)基类的成员,或- […]
(在我的例子中声明符id 是foo
和bar
)
相关文章:
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 在每个可变参数宏参数前面加上 C++ 函数参数的名称
- 为什么在函数参数前面添加 const 会出错?
- 为什么可变参数宏在“)”标记之前出现预期的主表达式失败,除非前面有命名参数
- C++14 lambda 的默认参数类型推导,具体取决于前面的参数
- 为什么不能在对象参数前面使用常量?
- 前面参数中的"&"和"*"是什么意思?
- 通过struct将参数传递给CreateThread(),并在不影响前面线程的情况下更改后续线程的成员
- 我们是否需要在嵌套类型的成员参数前面加上"::"?
- 新增C++ - 参数前面的符号