模板特化中的受保护成员访问错误
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
,基本上与您的代码相同。顺便说一句,它与模板专业化无关。
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
,基本上与您的代码相同。顺便说一句,它与模板专业化无关。