6

派生クラスで宣言を使用してstd::bind「パブリック」にした、プライベート基本クラスからメンバー関数を作成したいと思います。using関数を直接呼び出すと機能しますが、メンバー関数ポインターをバインドまたは使用するとコンパイルされないようです。

#include <functional>

struct Base {
    void foo() { }
};

struct Derived : private Base { 
    using Base::foo;            
};

int main(int, char **)
{
    Derived d;

    // call member function directly:
    // compiles fine
    d.foo();

    // call function object bound to member function:
    // no matching function for call to object of type '__bind<void (Base::*)(), Derived &>'
    std::bind(&Derived::foo, d)();

    // call via pointer to member function:
    // cannot cast 'Derived' to its private base class 'Base'
    (d.*(&Derived::foo))();

    return 0;
}

上記のエラー メッセージを見ると、問題Derived::fooはまだ であり、外部からBase::fooアクセスできないようBaseです。DerivedDerived

これは矛盾しているようです。直接呼び出し、バインドされた関数、および関数ポインターを同じ意味で使用できないようにする必要がありますか?

または(所有していないライブラリにある) を変更せずfooに、Derivedオブジェクトにバインドできるようにする回避策はありますか?BaseDerived

4

1 に答える 1

4

ここでの問題は、using 宣言が実際に行うことです。

struct Derived : private Base { 
    using Base::foo;            
};

これによりBase::foo、パブリック スコープが導入されDerivedますが、まったく新しい関数が作成されるわけではありません。次のように記述したことと同等ではありません。

struct Derived : private Base {
    void foo() { Base::foo(); }
}

まだありBase::foo()ます。using-declarationは、アクセス ルールとオーバーロード解決ルールに影響を与えるだけです。存在するのはそれだけなので、&Derived::foo実際には型がありますvoid (Base::*)()(! ではありません) 。isであるため、 へのポインターを介したメンバー アクセスは形式が正しくありません。これはかなり残念なことだと思います (「一貫性がない」というのは良い言葉です)。void (Derived::*)()fooBaseprivateBase

を呼び出す関数オブジェクトを引き続き作成できますfoo。メンバーへのポインターを使用することはできません。C++14 では、これは冗長であれば簡単になります (ここでは任意の引数を想定していますが、これvoid foo()は単に問題を単純化したものです)。

auto d_foo = [d](auto&&... args){ return d.foo(std::forward<decltype(args)>(args)...); }

C++11 では、可変個引数 template を使用して型を記述する必要がありますoperator()

于 2016-03-28T13:49:43.013 に答える