2016-05-10 7 views
1

の種類は、以下のコードを検討してください。この場合ラムダ式、共有ポインタこの

auto foo() { 
    // In this case, there is no explicit cast 
    // The type of ptr is no longer std::shared_ptr<T> 
    // It is std::shared_ptr<S> instead 
    auto ptr = shared_from_this(); 
    return [ptr](){ return ptr->bar(); }; 
} 

もはやコンパイル(いずれもGCCでも打ち鳴らすとともに)コード、:それは次のようにメソッドfooが変更されていない場合。

明らかに、最初の例で行ったことはキャスト後にコンパイルされますが、この場合でもラムダではbarが見えることが予想されます。そのコンテキストおよびインターフェイスの一部で到達可能ですSも同様である。

私は特に、それは5.1.5p8によるものであることを疑う:

ラムダ式の化合物のステートメントは、関数体[...]関数呼び出し演算子の収率が、[用.. 。]、のタイプと値を決定するこの [...]、複合ステートメントは、ラムダ式のコンテキストで考慮されます。実際に

は、打ち鳴らすによって返されるエラーは非常に明確である:

main.cppに:8:9:注意:唯一のタイプのオブジェクトにこのメンバーにアクセスすることができるT

私の控除権はありますか?
これは、前述の段落のために、共有ポインタの1つと一致しないthisポインタの型の決定に問題がありますか?

shared_ptrがゲームに参加するということは、私が理解するのが少し難しくなります。
正直なところ、両方のサンプルがコンパイルされるか、両方が失敗すると思います。

+1

あなたの 'static_pointer_cast'は消えました。また、 'return [ptr = shared_from_this()](){return ptr-> bar();を実行します。 }; 'は違った振る舞いをしますか? – ildjarn

+0

'shared_from_this'は' S'の共有ポインタを返します。これはもはや 'T'のものにキャストされません。したがって、実際には 'ptr'の型は' std :: shared_ptr 'です。私はもっ​​と読みやすい方法でそれを書いてほしいですか? – skypjack

+0

[Works for me](http://melpon.org/wandbox/permlink/hl00GHSN4JZ1Qhi1)をいくつかの簡単な変更の後に追加します。 –

答えて

3

保護されたアクセスの基本ルールに違反しているようです。私。全体はラムダや共有ポインタとは関係ありません。保護アクセスの古き良き規則は、初めから基本クラスの保護されたメンバーは派生クラスのオブジェクトを通してのみアクセス可能であると言っています。上で述べたのとは対照的に、Sの保護されたメンバーはSのオブジェクトからアクセスできませんが、タイプTのオブジェクトからアクセスできます。

全体のことは、次の簡単な例

struct S 
{ 
protected: 
    int i; 
}; 

struct T : S 
{ 
    void foo() 
    { 
     this->i = 5; // OK, access through `T` 

     T t; 
     t.i = 5; // OK, access through `T` 

     S s; 
     s.i = 5; // ERROR: access through `S`, inaccessible 

     S *ps = this; 
     ps->i = 5; // ERROR: access through `S`, inaccessible 
    } 
}; 
+1

それは 'S * s = this;のようになります。 s-> i = 5;そして、まあ...あなたは正しい。確かに単純で、ラムダは私を悲惨に失敗させました。 – skypjack

3

を低減することができ、私が質問にコメントが答えを持っていると思うし、私はここでクレジットを主張するために探していませんよ。

が最初にこの便利な無料の機能を定義します:

私はあなたが実際に基本クラスを知る必要さえ静的なキャストを呼び出すか、せずに静的なキャストの仕事を実行する「よりよい」方法に興味があるかもしれないと思いました

template<class T> 
auto shared_from_that(T* p) 
{ 
    return std::shared_ptr<T>(p->shared_from_this(), p); 
} 

その後の面でご正しく入力共有ポインタを取得:

auto foo() { 
    return [ptr = shared_from_that(this)](){ 
     return ptr->bar(); 
    }; 
} 

あらすじ:

std::shared_ptrという2つの引数のコンストラクタ(arg1のshared_ptrの制御ブロックとarg2の制御オブジェクトへのポインタを使用)が呼び出されます。

+0

あなたはまだ素敵なトリックのクレジットが本当にありがとうございます。ありがとうございました。静的なキャストを使用するよりも、これは何とか(意見に基づく回答の横に、パフォーマンスなどの点で)意味がありますか、それとも単に別の方法ですか? – skypjack

+0

@skypjack性能面では 'static_pointer_cast'よりも良くないかもしれませんが、メンテナンスは少なくて済みます。(a)あなたのクラスのタイプを知る必要がないので(リファクタリング時の間違いが少なくなります)、 )自動的に 'const'nessに従います。 –