2017-01-23 13 views
0

私はarduinoライブラリをいくつか書いていますが、読みやすさを向上させたい、構文上のsuggarを追加したいと思います。ヒープ上の匿名オブジェクトの連鎖

私は何をしたいのは次のようになりますように、ヒープ上のオブジェクトを作成します

Panel panel( 
    Button(1).on(Click(clickfunc)), 
    Button(2).on(Hold(holdfunc, 1000)) 
); 

(ボタン、クリック、ホールドは、すべてのクラスであり、内部的にリンクされたリストで管理(ので、彼らは上がりません)定数)。

私はこのように書こうとしましたが、私は一時的なものへの参照で問題を見つけました。

現在、私は使用することができます。

Button button1(1), button2(2); 
Click theClick(clickFunction); 
Hold theHold(holdFunction, 1000); 
Panel(button1.on(theClick), button2.on(theHold)); 

しかし、あなたが警戒しなければならないと、例えば入れていないので、これは上記とほぼ同じくらい読めないとエラーが発生しやすい傾向にあるがリンクされたリストを壊す別のボタンをクリックします。

今のように、クラスの一部を大幅に短縮した抜粋です。

class Button { 
    Handler *_first; 
    Button(int no){...} 
    Button & on(Handler &handler){ 
     handler._next = _first; 
     _first = &handler; 
     return *this; 
    } 
    void handle(int oldValue, int newValue) { 
     Handler *handler; 
     for(handler = _first; handler; handler = handler->_next){ 
      handler->handle(oldValue, newValue); 
     } 
    } 
} 
class Handler { 
    Handler *_next; 
    virtual void handle(int oldValue, int newValue) = 0; 
    ... 
} 
class Click : public Handler { 
    ... 
} 
class Hold : public Handler { 
    ... 
} 

これは必ずしもこのままである必要はありません。目標は、ユーザーが内部作業について多く知っている必要はなく、シンプルでクリーンなインターフェイスを備えたライブラリを提供することです。

+1

ノートでのライブの例です:彼らが持っていることはありませんので、ヒープ上のオブジェクトは、常に匿名です名前:決して変数ではありません。 –

+0

1行にしようとしたときに正確なエラーを追加できますか? – George

+0

@drescherjm:多分。しかし、なぜそれがヒープ上にないと思いますか? (あるいは、私はcppの文脈で "Heap"という言葉を間違って使っていますか?) – Scheintod

答えて

1

上記のコードで参照が不足している場合は、スタック上の要素を指すリファレンス(またはポインタ)を作成するリンクリストを作成している可能性があります。

私はあなたの署名はこのようになっていることも疑いがある:あなたの問題であなたを助けるために

Button& on(const Event& event) { /* ... */ } 

、私はこのような何かにあなたのon関数のシグネチャを変更することをお勧め:

template<typename EventType> 
Button& on(EventType&& event) { 

} 

こうすることで、実際にオブジェクトをヒープに転送し、リンクされたリストにオブジェクトを挿入することができます:

struct Handler { 
    virtual void handle(int oldValue, int newValue) = 0; 

    // Defaulted virtual destructor 
    virtual ~Handler() = default; 
}; 

template<typename T> 
struct HandlerImpl : Handler { 
    // constructors 
    HandlerImpl(T h) : handler{std::forward<T>(h)} {} 

    void handle(int oldValue, int newValue) { 
     handler.handle(oldValue, newValue); 
    } 

    // We use the compiler generated destructor 

private: 
    remove_rvalue_reference_t<T> handler; 
}; 

template<typename HandlerType> 
Button& on(HandlerType&& event) { 
    // See the code example below 
} 

残りのコードではどのような変更が加えられましたか?

あなたが投稿した両方の構文がサポートされました。最初の構文は変数を移動して保持します。 2番目の構文では、イベントへの参照のみが保持され、イベントの有効期間はボタンの寿命と同じかそれ以上であると想定されます。

また、ClickおよびHoldは、クラスを拡張する必要もなく、仮想関数または仮想デストラクタを必要としません。

あなたは私はあなたがButtonのために適用され、あなたが好きなウィジェットタイプにすることができます示した。このパターンを参照を保持し、代わりにコピーを使用し、std::remove_reference_t.

remove_rvalue_reference_tを置き換えるために2番目の構文をしたくない場合。


はここremove_rvalue_reference_tが実装されている方法は次のとおりです。

template<typename T> struct remove_rvalue_reference { using type = T; }; 
template<typename T> struct remove_rvalue_reference<T&&> { using type = T; }; 
template<typename T> using remove_rvalue_reference_t = typename remove_rvalue_reference<T>::type; 

あなたのコードの例を掲載しているので、私は今、それが上記のコードで作業できるように、それを変換することができます。

まず、好きなリストは遅く、手巻きの好きなリストは悪いです。 std::vectorを使用することを強くお勧めします。第2に、std::unique_ptrは、所有者のポインタを保持するための好ましい方法です。それでは、これと上記の手順に従うことで、あなたのコードは次のようになります。

struct Button { 
    std::vector<std::unique_ptr<Handler>> _handlers; 

    Button(int no) { /* ... */ } 

    // This function will work for any type that 
    // happen to have an `handle` function. 
    template<typename H> // <--- H is the handler type 
    Button& on(H&& handler) { // H&& in this case means forwarding reference. 
     // We add (emplace) a new HandlerImpl, allocated on the heap using `std::make_unique` 
     _handlers.emplace_back(
      std::make_unique<HandlerImpl<H>>(std::forward<H>(handler)) 
     ); 

     return *this; 
    } 

    void handle(int oldValue, int newValue) { 
     // We use a range for loop here to iterate on the vector 
     for (auto&& handler : _handlers) { 
      handler->handle(oldValue, newValue); 
     } 
    } 
}; 

// We do not extends anything 
struct Click { 
    // Notice that the function is not virtual 
    void handle(int oldVal, int newVal) {/* ... */} 
}; 

struct Hold { 
    void handle(int oldVal, int newVal) {/* ... */} 
}; 

ここColiru

+0

答えをありがとう!しかし、神聖なたわごと(!)今私は最初に深くすべての種類のC + +のものを掘る必要がない私は手がかりを持っていない。 (私には恥ずかしがりますが、私は魔法を求めました) – Scheintod

+0

@Scheintodあなたのコードで動作するより具体的な例を追加しました。 –

+0

もう一度ありがとうございます。まだ物事を把握しようとしています:)私はarduinoで私はstd :: vectorを持っていないと思う。 Hm。 std :: unique_ptrどちらも好きではありません... – Scheintod

関連する問題