3
class safe_bool_base {
protected:
  void this_type_does_not_support_comparisons() const {}
};

template <typename T=void> class safe_bool : public safe_bool_base {
public:
  void func() {
    &safe_bool::this_type_does_not_support_comparisons;
    &safe_bool_base::this_type_does_not_support_comparisons;
  }
};

template<> class safe_bool<void> : public safe_bool_base {
public:
  void func() {
    &safe_bool::this_type_does_not_support_comparisons;
    &safe_bool_base::this_type_does_not_support_comparisons;
  }
};

错误信息:

zzz.cpp: In member function 'void safe_bool<void>::func()':
zzz.cpp:7:10: error: 'void safe_bool_base::this_type_does_not_support_comparison
s() const' is protected
 void this_type_does_not_support_comparisons() const {}
      ^
zzz.cpp:22:24: error: within this context
   &safe_bool_base::this_type_does_not_support_comparisons;
                    ^

我想知道为什么在模板专业化中无法访问受保护的成员。这些代码毫无意义,仅用于测试。

4

1 回答 1

3

当public从基类继承时,它的protected成员成为派生类的protected成员,可以在派生类的成员函数中访问。请注意,它们只能通过派生类本身(及其派生类)访问。但是受保护的成员不能通过基类访问。这就是为什么&safe_bool::this_type_does_not_support_comparisons;有效但&safe_bool_base::this_type_does_not_support_comparisons;无效。

从标准来看,11.4/1 受保护的成员访问 [class.protected]

(强调我的)

当非静态数据成员或非静态成员函数是其命名类 ([class.access.base])114 的受保护成员时,将应用超出条款 [class.access] 中所述的附加访问检查早些时候,由于引用发生在某个 C 类的朋友或成员中,所以授予对受保护成员的访问权限。如果访问要形成指向成员 ([expr.unary.op]) 的指针,则嵌套名称说明符应表示 C 或从 C 派生的类。所有其他访问都涉及(可能是隐式的)对象表达式([expr.ref])。在这种情况下,对象表达式的类应为 C 或从 C 派生的类。 [ 示例:

class B {
protected:
  int i;
  static int j;
};

class D1 : public B {
};

class D2 : public B {
  friend void fr(B*,D1*,D2*);
  void mem(B*,D1*);
};

...
void D2::mem(B* pb, D1* p1) {
  pb->i = 1;                    // ill-formed
  p1->i = 2;                    // ill-formed
  i = 3;                        // OK (access through this)
  B::i = 4;                     // OK (access through this, qualification ignored)
  int B::* pmi_B = &B::i;       // ill-formed
  int B::* pmi_B2 = &D2::i;     // OK
  j = 5;                        // OK (because j refers to static member)
  B::j = 6;                     // OK (because B::j refers to static member)
}

...

—结束示例]

请注意标准示例代码中的语句int B::* pmi_B = &B::i; // ill-formed,基本上它与您的代码相同。顺便说一句,它与模板专业化无关。

于 2016-07-29T11:16:29.417 回答