2016-03-28 11 views
6

std::bind私はプライベートベースクラスのメンバ関数に派生クラスのusing -declarationで "public"を作成したいと思います。関数が直接働く呼び出し、それがコンパイルされないメンバ関数ポインタを使用して結合または思わ: 非公開継承メンバ関数へのバインド

#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から Derived Derivedの外側にアクセスしてください。

これは矛盾しているようです - 私はダイレクトコール、バウンド関数、および関数ポインタを同じ意味で使用できないはずですか?

私は、好ましくは、(私が所有していないライブラリ内にある)BaseまたはDerivedを変更せずに、Derivedオブジェクト上fooにバインドせてしまうの回避策はありますか?

+0

回避策として、ラムダ '[&d](){d.foo();}を使うことができます。 } '。 – Holt

答えて

4

ここでの問題は、using宣言が実際に何をするかです:DerivedにパブリックスコープにBase::fooをもたらしますが、それは全く新しい機能を作成しません

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

。それは書かれたと同等ないです:

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

のみBase::foo()がまだあります。 使用宣言は、アクセス規則と過負荷解決規則に影響を与えます。したがって&Derived::fooは実際にはタイプvoid (Base::*)()(かつvoid (Derived::*)()!ではありません!)が存在するので、それは存在するのはfooです。 Baseprivateであるため、Baseへのポインタによるメンバアクセスは不正です。私はこれがかなり不幸であることに同意する(「不一致」は良い言葉である)。

fooを呼び出す関数オブジェクトを作成することはできます。メンバーへのポインタは使用できません。 C++ 11では

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

、あなたが書く必要があるだろう:冗長(私はvoid foo()は単に問題を簡略化したものであることをここに任意の引数を仮定しています)場合はC++ 14では、これは簡単になりVariadicテンプレートoperator()を持つ型。

+0

ラムダを使ったニースは、ポインタを避ける興味深い方法です! C++ 11を必要としない回避策はありますか? –

+0

@AndersJohanssonあなたはすでに 'std :: bind'を使用していますか?とにかく、どんなラムダも、常に同等の構造体 'struct D_Foo {D d;}として書くことができます。 void operator()(){d.foo(); }}; ' – Barry

+0

私のテストケースは' std :: bind'のC++ 11ですが、実際には私は 'boost :: bind'でC++ 03に限定されています。 。上記のような構造体のようなサウンドは、そのトリックを行う必要があります。ありがとう! –

関連する問題