5

誰かがこのコードの理由を説明してもらえますか?

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いるため、基本クラスの保護されたメンバーにアクセスできない理由がわかりません。

私は何かが足りないのですか?

4

3 に答える 3

9

これはおそらく役立つはずです(テンプレート以外の状況でも再現可能)

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

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

int main(){
}

VSは「'A:: f':クラス'A'で宣言された保護されたメンバーにアクセスできません」を提供します

同じコードに対して、Comeauは

「ComeauTest.c」、7行目:エラー:保護された関数「A :: f」(3行目で宣言)は、「A」ポインタまたはオブジェクトからアクセスできませんvoid g(){&A :: f;} ^

"ComeauTest.c"、7行目:警告:式は効果がありませんvoid g(){&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)へのポインタ、参照、またはオブジェクトを介して行う必要があります。メンバーへのポインタであるnested-name-specifierは、派生クラス(またはそのクラスから派生したクラス)に名前を付ける必要があります。

したがって、演算子関数内の戻り値を次のように変更します

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(){} 
于 2010-09-07T10:07:08.187 に答える
1

これはテンプレートとは何の関係もないと思います。サンプルコードはこれに減らすことができますが、それでも同等のエラーが発生します。

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


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

問題は、パブリックインターフェイスで保護されたメンバーにメンバー関数ポインタを返すことができないことだと思います。編集:真実ではありません...

于 2010-09-07T09:49:25.677 に答える
0

Chubsdadの回答は、テンプレートの特殊化にエラーがある理由についてのあなたの質問を明確にします。

次のC++標準ルール

14.7.2 / 11通常のアクセスチェックルールは、明示的な
インスタンス化
を指定するために使用される名前には適用されません。[注:特に、関数
宣言子で使用されるテンプレート引数と名前(パラメーター型、戻り型、例外仕様を含む)は
、通常はアクセスできないプライベート型またはオブジェクトである可能性があり、テンプレートは
メンバーテンプレートまたはメンバー関数である可能性があります通常はアクセスできません。—巻末注]

ジェネリックテンプレートのインスタンス化がエラーをスローしない理由を説明します。プライベートアクセス指定子がある場合でもスローされません。

于 2010-09-07T11:45:57.747 に答える