Could someone explain me why this code:
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() {}
};
Produces the following compiler error ?
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'
Since both safe_bool templates derive from safe_bool_base, I don't understand why one can't access a protected member of the base class.
Am I missing something ?
This should probably help (reproducible in a non template situation also)
struct A{
protected:
    void f(){}
};
struct B : A{
    void g(){&A::f;}        // error, due to Standard rule quoted below
};
int main(){
}
VS gives "'A::f' : cannot access protected member declared in class 'A'"
For the same code, Comeau gives
"ComeauTest.c", line 7: error: protected function "A::f" (declared at line 3) is not accessible through a "A" pointer or object void g(){&A::f;} ^
"ComeauTest.c", line 7: warning: expression has no effect void g(){&A::f;}
Here is the fixed code which achieves the desired intentions
struct A{
protected:
    void f(){}
};
struct B : A{
    void g(){&B::f;}        // works now
};
int main(){
}
So, why does the first code snippet not work?
This is because of the following rule in the C++ Standard03
11.5/1- "When a friend or a member function of a derived class references a protected nonstatic member function or protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11.102) Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).
So change the return within operator functions as follows
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; 
EDIT 2: Please ignore my explanations. David is right. Here is what it boils down to.
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(){} 
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With