2012-04-26 13 views
5

私はC#でのプロパティのアイデアが本当に好きです。ちょっとしたプロジェクトとして、私はC++でそれらを実装するという考え方を変えてきました。私はhttps://stackoverflow.com/a/5924594/245869のようにうまくいっていますが、lambdaと非静的なデータメンバの初期化によって、このアイデアで非常に良い構文を使用できるようになるとは思えませんでした。ここに私の実装です:C++ 11;非静的データメンバ初期化は他のデータメンバにアクセスできますか?

#include <iostream> 
#include <functional> 

using namespace std; 


template< typename T > 
class property { 

public: 
    property(function<const T&(void)> getter, function<void(const T&)> setter) 
     : getter_(getter), 
      setter_(setter) 
    {}; 

    operator const T&() { 
     return getter_(); 
    }; 

    property<T>& operator=(const T& value) { 
     setter_(value); 
    } 

private: 
    function<const T&(void)> getter_; 
    function<void(const T&)> setter_; 

}; 


class Foobar { 

public: 
    property<int> num { 
     [&]() { return num_; }, 
     [&](const int& value) { num_ = value; } 
    }; 

private: 
    int num_; 

}; 


int main() { 
    // This version works fine... 
    int myNum; 
    property<int> num = property<int>(
     [&]() { return myNum; }, 
     [&](const int& value) { myNum = value; } 
    ); 
    num = 5; 

    cout << num << endl; // Outputs 5 
    cout << myNum << endl; // Outputs 5 again. 

    // This is what I would like to see work, if the property 
    // member of Foobar would compile... 
    // Foobar foo; 
    // foo.num = 5; 

    // cout << foo.num << endl; 

    return 0; 
} 

私は[main()の例を参照してください]通常、私のプロパティクラスを使用することができますが、G ++ 4.7とMinGWのは、特にデータとしてプロパティを使用しての私の試みのために気にしません。メンバー:

\property.cpp: In lambda function: 
\property.cpp:40:7: error: invalid use of non-static data member 'Foobar::num_' 

だから、私の財産の実装作品のコンセプトようだが、私は私のラムダ関数から他のデータメンバにアクセスすることはできませんので、それは無駄になるかもしれません。私がここでやろうとしていることをスタンダードがどのように定義しているのかは分かりませんが、私は運がまったくないのですか?

+3

関連性:移動専用のタイプをサポートし、一般的に不要なコピーを避けるために、コンストラクタで 'getter_(std :: move(getter))、setter_(std :: move(setter))'を使用します。 –

+0

質問:面白いこととは別に、私は単純な 'int&'がもっと有用であると信じています。シンプルなリファレンスに比べて、あなたのソリューションの利点は何ですか? (それ自体は役に立たない...) –

+0

@ R.MartinhoFernandes私は完全に同意する。 'property <>'自体もコピー/移動セマンティクスをサポートする必要があり、プロパティを持つクラスをコピー/移動することができます。私はコンセプトを働かせるまで実装をできる限り最小限に抑えたいと思っていました。しかし、ありがとう! @MatthieuM。 –

答えて

2

あなたのプロパティは、オブジェクト(Foobarのインスタンス)とは異なるオブジェクト(property<int>のインスタンス)です。したがって、そのメンバー関数はと異なるものになります。アクセスする必要があるのはnum_なので、そうすることはできません。ラムダが非スタティックメンバ関数Foobarで定義されていた場合、ラムダはその関数のthis引数を取得し、囲みオブジェクトのメンバ(明示的にはthis->num_)にアクセスしていました。しかし、ラムダは、非静的データメンバーが実際には存在しないクラスで定義されます。ラムダになった場合、どれもFoobarnum_num_)のアクセス権があるでしょうか?

私が見る最も簡単な解決策は、囲みオブジェクトへのポインタを格納するプロパティです。そうすれば、非静的メンバーに自由にアクセスできます。欠点は宣言が少し複雑であることです(property<int, Foobar> numを実行する必要があります)、thisポインタを渡してプロパティを初期化する必要があることです。クラス内でそれを行うことができないので、コンストラクタの初期化リストになければならないため、C++ 11のデータメンバの初期化の利点が失われます。

この時点でthisは、Foobarのコンストラクタにプロパティの初期化を移した場合には、(暗黙のうちに)値を参照してキャプチャするようにラムダに利用可能になります。 ):

Foobar::Foobar(): 
    num { 
     [this]() { return this->num_; }, 
     [this](const int& value) { this->num_ = value; } 
    } 
{ 
} 

は誰でも、呼び出すことを起こるものは何でもコンストラクタに渡される、クラス定義内の非静的メンバの初期化のために利用可能であるthisかどうか知っていますか?私はそうではないと思っていますが、そうであれば、同じ構造がクラス定義の中で機能します。

+0

私はちょうどこれが特別なケースであるという一般的な問題を追加したかっただけです。つまり、内部オブジェクトの外側オブジェクトへのポインタを格納せずに、オブジェクトから囲みオブジェクトへのアクセスは、常にC++では扱いにくいものでした。それはできますが、それはいいとは思わないと私は関与するポインタの魔法は、厳密なエイリアスのルールを破ると確信しています... – cvoinescu

+0

私はこの質問をキャプチャ句を作ることを[この]データメンバーへのアクセス、私はなぜそれが必要だったか分からなかったが、あなたの答えは私のためにそれをクリアします。ありがとう!これをコンストラクタのイニシャライザリストに移動する必要はありません。私がそれを完璧に動作させるようにコードをキャプチャ句で変更します。 –

+0

しかし、私の元々の質問にはあまり関係していない厄介な問題が残っています。あなたが説明した理由のため、ラムダは私の 'Foobar'クラスのプライベートデータメンバーにアクセスすることができません。私はこの仕事をするために 'Foobar'から' property 'を正しく友人にする方法を考え出していません。データメンバを 'public'に設定すると完全にコンパイルされ実行されるので、私はfriendingが解決策だと思います。 –

関連する問題