C++11;非静态数据成员初始化能否访问其他数据成员? 我很喜欢C中的属性,作为一个小的侧面项目,我一直在用C++实现这些想法。我遇到了这个看起来相当不错的示例,但我忍不住认为lambdas和非静态数据成员初始化可能会使使用一些非常好的语法来实现这个想法成为可能。以下是我的实现: #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; }

C++11;非静态数据成员初始化能否访问其他数据成员? 我很喜欢C中的属性,作为一个小的侧面项目,我一直在用C++实现这些想法。我遇到了这个看起来相当不错的示例,但我忍不住认为lambdas和非静态数据成员初始化可能会使使用一些非常好的语法来实现这个想法成为可能。以下是我的实现: #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; },c++,gcc,lambda,c++11,mingw,C++,Gcc,Lambda,C++11,Mingw,因此,我的属性实现的概念似乎是可行的,但它可能是徒劳的,因为我无法从lambda函数访问其他数据成员。我不确定标准是如何定义我在这里要做的事情的,是我完全不走运,还是我只是在这里没有做正确的事情?您的属性是属性的不同对象实例,与包含Foobar的对象实例不同。因此,它的成员函数将以不同的方式传递给您,而不是您需要访问num\的函数,因此您不能这样做。如果lambda是在Foobar的一个非静态成员函数中定义的,那么它们将捕获该函数的this参数,并可以显式访问封闭对象的成员,如this->num

因此,我的属性实现的概念似乎是可行的,但它可能是徒劳的,因为我无法从lambda函数访问其他数据成员。我不确定标准是如何定义我在这里要做的事情的,是我完全不走运,还是我只是在这里没有做正确的事情?

您的属性是属性的不同对象实例,与包含Foobar的对象实例不同。因此,它的成员函数将以不同的方式传递给您,而不是您需要访问num\的函数,因此您不能这样做。如果lambda是在Foobar的一个非静态成员函数中定义的,那么它们将捕获该函数的this参数,并可以显式访问封闭对象的成员,如this->num\ux。但是lambda是在类中定义的,其中非静态数据成员实际上并不存在。如果lambda确实有权访问num_,那么哪个num_,哪个Foobar实例会是这样的

我看到的最简单的解决方案是让属性存储指向封闭对象的指针。这样,它就可以自由访问其非静态成员。缺点是声明稍微复杂一些,您必须执行属性num,并且需要通过传递this指针来初始化属性。因此,您将无法在类中执行此操作,它必须位于构造函数的初始化列表中,因此否定了C++11的数据成员初始化的优势

在这一点上,lambda可以通过值而不是引用来捕获!因此,如果您将属性的初始化移到Foobar的构造函数中,那么您的代码实际上只需要很少的更改:

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

是否有人知道,在类定义中,传递给调用的构造函数的这个函数是否可用于非静态成员初始化?我怀疑不是这样,但如果是这样的话,相同的构造将在类定义中起作用。

无关:您可能希望构造函数中的getter_std::movegetter、setter_std::movesetter支持仅移动类型,并通常避免无关副本。问题:除了有趣之外,我相信简单的int&将更有用。与简单的参考相比,您的解决方案有什么优势?这本身是无用的。。@R.MartinhoFernandes我完全同意。属性本身还需要支持复制/移动语义,以便可以复制/移动具有属性的类。我希望尽可能少地实现,直到我可以让这个概念发挥作用。谢谢你@马蒂厄姆。属性提供与get/set方法相同的好处,但允许客户端使用更简洁的语法。一旦您的所有类都有get/set方法,它可能会变得丑陋,只需询问任何Java开发人员,即obj1.setSomethingobj2.getSomething与obj1.something=obj2.something。获取/设置时,getter/setter允许对象对数据本身执行一些操作,或者转换数据,或者执行幕后操作。例如,对于一个大对象的数据成员,我可以等到调用它的getter来加载它,而不是在构造时强制加载它。@BretKuhns:我个人发现多个setter等同于数据包。因此,我当然不会让他们看起来更酷。。。但这是主观的。我只想补充一个更一般的问题,即在特定的情况下,即从对象到封闭对象的访问,而不在内部对象中存储指向外部对象的指针,在C++中总是很棘手。这是可以做到的,但看起来不太好,而且我确信所涉及的指针魔术打破了严格的别名规则……我在问了这个问题大约一个小时后发现,使用capture子句[this]可以修复对数据成员的访问,我不确定为什么有必要这样做,但你的回答为我澄清了这一点。谢谢事实证明,您不需要将其移动到构造函数的初始值设定项列表中。在代码就位的情况下修改capture子句效果很好。不过,还有一个隐约可见的问题,与我最初的问题不太相关。由于您解释的原因,lambda无法访问我的Foobar类的私有数据成员。我还没有完全弄明白如何正确地从Foobar创建好友属性来实现这一点。将数据成员设置为public可以完美地编译和运行,因此我认为友谊是解决方案。@Bret:不可能为lambda建立朋友关系,因为在此上下文中不可能声明其类型。@I ldjarn我相信,根据cvoinescu的解释,lambdas的背景应该与财产有关。我以后才能使用它,但我不熟悉如何为模板类建立朋友关系。但是,也许你是对的,而lambdas本身就是问题所在,正如你所指出的,这将是一条死胡同。
Foobar::Foobar():
    num {
        [this]() { return this->num_; },
        [this](const int& value) { this->num_ = value; }
    }
{
}