2012-04-26 2 views
5

저는 C#에서 속성에 대한 아이디어를 정말 좋아합니다. 그리고 작은 프로젝트로서, 저는 C++로 구현하는 아이디어를 고수해 왔습니다. 꽤 좋은 것처럼 보인이 예제 https://stackoverflow.com/a/5924594/245869을 만났지 만, lambda와 non-static 데이터 멤버 초기화가이 아이디어와 함께 아주 멋진 구문을 사용할 수 있다고 생각할 수는 없습니다.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; 
} 
나는 일반적으로 내 재산 클래스를 사용할 수 있습니다

가 데이터로 속성을 사용하여에 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 <>'자체는 속성을 가진 클래스가 복사/이동 될 수 있도록 복사/이동 의미를 지원해야한다. 개념을 작동시킬 때까지 구현을 가능한 한 최소화하고 싶었습니다. 그래도 고마워! –

답변

2

속성에 포함 된 개체 (인스턴스 Foobar)의 다른 개체 (property<int>의 인스턴스)입니다. 따라서 그 멤버 함수는 num_에 액세스해야하는 것이 아닌 다른 this을 전달하므로 그렇게 할 수 없습니다. 람다가 비 정적 멤버 함수 인 Foobar에 정의 된 경우 해당 함수의 this 인수를 캡처하여 해당 객체의 멤버 (명시 적으로 this->num_)에 액세스 할 수 있습니다. 그러나 람다는 클래스에서 정의되며 비 정적 데이터 멤버가 실제로 존재하지 않습니다. 람다 을 수행 한 경우 num_() 중 어떤 것이 Foobar일까요?

가장 쉬운 해결책은 둘러싼 개체에 대한 포인터를 저장하는 속성입니다. 그렇게하면 비 정적 멤버에 자유롭게 액세스 할 수 있습니다. 단점은 선언이 다소 복잡하다는 것입니다 (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

나는이 질문을 한 후 약 1 시간을 발견했습니다 [이] 수정 조항 데이터 회원에 대한 액세스, 왜 그것이 필요한지 잘 모르겠지만 귀하의 대답은 나를 위해 그것을 지 웁니다. 감사! 이것을 생성자의 이니셜 라이저 목록으로 옮길 필요가 없습니다. 캡션 절을 코드로 변경하면 완벽하게 작동합니다. –

+0

그래도 원래의 질문과 관련이없는 문제가 하나 남아 있습니다. 설명하신 이유 때문에 람다는 제 'Foobar'클래스의 개인 데이터 멤버에 액세스 할 수 없습니다. 나는이 작업을하기 위해'Foobar'의'property '을 적절히 친구로 사귀는 방법을 알지 못했습니다. 데이터 멤버를 'public'으로 설정하면 완벽하게 컴파일되고 실행되므로 friending이 해결책이라고 생각합니다. –

관련 문제