Ошибка доступа к защищенному члену в специализации шаблона

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

Интересно, почему защищенный член нельзя посетить в шаблоне специализации. Коды не имеют смысла и просто для тестирования.

1

Решение

Когда public наследуется от базового класса, его защищенные члены становятся «защищенными членами производного класса, к которым можно получить доступ в функциях-членах производного класса». Обратите внимание, что они доступны только через сам производный класс (и его производные классы). Но защищенные члены не могут быть доступны через базовый класс. Вот почему &safe_bool::this_type_does_not_support_comparisons; работает но &safe_bool_base::this_type_does_not_support_comparisons; не делает.

Из стандарта, $ 11,4 / 1 Защищенный членский доступ
[Class.protected]
:

(подчеркни мой)

Дополнительная проверка доступа помимо описанных ранее в пункте
[class.access] применяется, когда нестатический элемент данных или нестатический
функция-член является защищенным членом своего класса именования
([class.access.base]) 114 Как описано ранее, доступ к защищенному
участник предоставлен, потому что ссылка встречается у друга или участника
какого-то класса 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 в примере кода из стандарта, в основном это тот же случай вашего кода. Кстати, это не имеет ничего общего с шаблонной специализацией.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]