Странная ошибка компилятора и наследование шаблона - PullRequest
5 голосов
/ 07 сентября 2010

Может кто-нибудь объяснить мне, почему этот код:

class safe_bool_base
{ //13
    protected:

        typedef void (safe_bool_base::*bool_type)() const;

        void this_type_does_not_support_comparisons() const {} //18

        safe_bool_base() {}
        safe_bool_base(const safe_bool_base&) {}
        safe_bool_base& operator=(const safe_bool_base&) { return *this; }
        ~safe_bool_base() {}
};

template <typename T=void> class safe_bool : public safe_bool_base
{
    public:

        operator bool_type() const
        {
            return (static_cast<const T*>(this))->boolean_test() ? &safe_bool_base::this_type_does_not_support_comparisons : 0;
        }

    protected:

        ~safe_bool() {}
};

template <> class safe_bool<void> : public safe_bool_base
{
    public:

        operator bool_type() const
        {
            return (boolean_test() == true) ? &safe_bool_base::this_type_does_not_support_comparisons : 0; //46
        }

    protected:

        virtual bool boolean_test() const = 0;
        virtual ~safe_bool() {}
};

Выдает следующую ошибку компилятора?

c:\project\include\safe_bool.hpp(46) : error C2248: 'safe_bool_base::this_type_does_not_support_comparisons' : cannot access protected member declared in class 'safe_bool_base'
c:\project\include\safe_bool.hpp(18) : see declaration of 'safe_bool_base::this_type_does_not_support_comparisons'
c:\project\include\safe_bool.hpp(13) : see declaration of 'safe_bool_base'

Поскольку оба шаблона safe_bool получены из safe_bool_base, я не понимаю, почему нельзя получить доступ к защищенному члену базового класса.

Я что-то упустил?

Ответы [ 3 ]

9 голосов
/ 07 сентября 2010

Это, вероятно, должно помочь (воспроизводится также и в не шаблонной ситуации)

struct A{
protected:
    void f(){}
};

struct B : A{
    void g(){&A::f;}        // error, due to Standard rule quoted below
};

int main(){
}

VS дает "A :: f": не может получить доступ защищенный член объявлен в классе 'А' "

Для того же кода, Комо дает

"ComeauTest.c", строка 7: ошибка: защищенная функция "A :: f" (объявлена ​​в строка 3) недоступен через указатель «A» или объект void g () {& A :: f;} ^

"ComeauTest.c", строка 7: предупреждение: выражение не имеет никакого эффекта void г () {& A :: F;}

Вот фиксированный код, который достигает желаемых намерений

struct A{
protected:
    void f(){}
};

struct B : A{
    void g(){&B::f;}        // works now
};

int main(){
}

Итак, почему первый фрагмент кода не работает?

Это из-за следующего правила в C ++ Standard03

11.5 / 1- "Когда друг или функция-член производного класса ссылаются защищенная нестатическая функция-член или защищенный нестатический элемент данных базовый класс, применяется проверка доступа в дополнение к описанным ранее в пункте 11.102) За исключением случаев формирования указатель на член (5.3.1), доступ должен быть через указатель на, ссылка или объект сам производный класс (или любой класс происходит из этого класса) (5.2.5). Если доступ должен сформировать указатель на член, спецификатор вложенного имени должен назвать производный класс (или любой класс, производный от этого класса).

Итак, измените возврат в операторных функциях следующим образом

return (boolean_test() == true) ? &safe_bool<void>::this_type_does_not_support_comparisons : 0; //46 

return (static_cast<const T*>(this))->boolean_test() ? &typename safe_bool<T>::this_type_does_not_support_comparisons : 0; 

РЕДАКТИРОВАТЬ 2: Пожалуйста, игнорируйте мои объяснения. Дэвид прав. Вот к чему это сводится.

struct A{
protected:
    int x;
};

struct B : A{
    void f();
};

struct C : B{};

struct D: A{            // not from 'C'
};

void B::f(){
    x = 2;         // it's own 'A' subobjects 'x'. Well-formed

    B b;
    b.x = 2;       // access through B, well-formed

    C c;
    c.x = 2;       // access in 'B' using 'C' which is derived from 'B', well-formed.

    D d;
    d.x = 2;       // ill-formed. 'B' and 'D' unrelated even though 'A' is a common base
}

int main(){} 
1 голос
/ 07 сентября 2010

Не думаю, что это связано с шаблонами. Ваш пример кода может быть уменьшен до этого, и он все еще дает эквивалентную ошибку:

class A
{
    protected:
        typedef void (A::*type)() const;
        void foo() const {}
};


class B : public A
{
    public:
        operator type() const
        {
            return &A::foo;
        }
};

Я считаю, что проблема в том, что вы не можете вернуть указатели на функции-члены защищенным членам в общедоступном интерфейсе. ( Редактировать: не верно ... )

0 голосов
/ 07 сентября 2010

Ответ Chubsdad проясняет ваш вопрос, почему произошла ошибка для специализации шаблона.

Теперь следующее стандартное правило C ++

14.7.2 / 11 Обычные правила проверки доступа не применяются к именам, используемым для указания явного
конкретизации
. [Примечание: В частности, аргументы и имена шаблонов используются в функции
декларатор (включая типы параметров, типы возвращаемых данных и спецификации исключений) может иметь значение
частные типы или объекты, которые обычно не были бы доступны, и шаблон может быть
шаблон члена или функция-член, которые обычно не были бы доступны. - примечание]

объясняет, почему создание экземпляра универсального шаблона не выдает ошибку. Он не выдаст, даже если у вас есть личный спецификатор доступа.

...