Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11; Can non-static data member initializations access other data members?

I really like the idea of properties in C#, and as a little side project, I've been tinkering with the idea of implementing them in C++. I ran into this example https://stackoverflow.com/a/5924594/245869 which seems fairly nice, but I couldn't help but think that lambdas and non-static data member initialization may make it possible to use some very nice syntax with this idea. Here's my implementation:

#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;
}

I can use my property class normally [see the example in main()], but MinGW with g++4.7 doesn't particularly care for my attempt at using the property as a data member:

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

So it seems the concept of my property implementation works, but it might be in vain because I can't access other data members from my lambda functions. I'm not sure how the standard defines what I'm trying to do here, am I completely out of luck, or am I just not doing something right here?

like image 434
Bret Kuhns Avatar asked Apr 26 '12 12:04

Bret Kuhns


People also ask

Can static member functions access non-static data members?

Static Function: It is a member function that is used to access only static data members. It cannot access non-static data members not even call non-static member functions. It can be called even if no objects of the class exist.

Where can a non-static reference member variable of a class be initialized?

Member initialization Non-static data members may be initialized in one of two ways: 1) In the member initializer list of the constructor.

Can we access non-static data member without using object?

To access a non-static method, we need an object instance to access it.

Can I initialize Non-static data member inside static block?

Yes... a non-static method can access any static variable without creating an instance of the class because the static variable belongs to the class.


1 Answers

Your property is a different object (instance of property<int>) from the containing object (instance of Foobar). As such, its member functions get passed a different this, not the one you'd need to access num_ -- so you can't do it that way. If the lambdas were defined in a non-static member function of Foobar, they would have captured that function's this argument and would have had access to the enclosing object's members (explicitly, as this->num_). But the lambdas are defined in the class, where the non-static data members don't actually exist. If the lambdas did have access to num_, which num_, of which instance of Foobar, would have been that?

The easiest solution that I see is for the property to store a pointer to the enclosing object. That way, it can freely access its non-static members. The downside is that the declaration is slightly more complex (you'd have to do property<int, Foobar> num) and you'd need to initialize the property by passing the this pointer. So you won't be able to do it in the class, it would have to be in the constructor's initialization list, hence negating the advantage of C++11's data member initialization.

At that point, this would be available to the lambdas to capture anyway (by value, not by reference!) so your code would actually work with minimal changes, if you moved the initialization of the property to Foobar's constructor(s):

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

Does anyone know whether this, as passed to whatever constructor happens to be invoked, is available for non-static member initialization in the class definition? I suspect it isn't, but if it were, the same construction would work inside the class definition.

like image 138
cvoinescu Avatar answered Oct 15 '22 01:10

cvoinescu