模板特化中的受保护成员访问错误

Protected member access error in template specialization

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;
                    ^

我想知道为什么在模板特化中不能访问受保护的成员。代码无意义,仅供测试。

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

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

(强调我的)

An additional access check beyond those described earlier in Clause [class.access] is applied when a non-static data member or non-static member function is a protected member of its naming class ([class.access.base])114 As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member ([expr.unary.op]), the nested-name-specifier shall denote C or a class derived from C. All other accesses involve a (possibly implicit) object expression ([expr.ref]). In this case, the class of the object expression shall be C or a class derived from C. [ Example:

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)
}

...

— end example ]

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