我们是否需要在嵌套类型的成员参数前面加上"::"?

Do we need to prefix member arguments of nested type with "::"?

本文关键字:前面 参数 成员 是否 嵌套类型 我们      更新时间:2023-10-16

例如,考虑以下名称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 foobar)