GorillazOnPlane
GorillazOnPlane

Reputation: 401

C++ Calling method on members "by name", like Pythons `__getattribute__()` using pointer to member

I want to do something similar to Python's __getattribute()__, but in C++. It feels like I should be using some kind of pointer-to-member, but I can't really figure out how to get started.

The gist of what I want to do is define a class that contains pointers to other instances of the same class, as well as various data members. Then I want a method that can be called to do a specific operation, using a specific data member.

For example, if the class is like this:

class C{
    public:
    C* linked1;
    C* linked2;

    double d1;
    double d2;
    
    C(double d1, double d2) : d1{d1}, d2{d2} {};
    double add(<pointer to member or something?>){
        return linked1-><attribute> + linked2-><attribute> + <attribute>
    }
};

I want to be able to call the method add() like this:

C c1{1., 2.};
C c2{3., 4.};
C c3{5., 6.};

c1.linked1 = &c2;
c1.linked2 = &c3;

double a1 = c1.add(<use d1>); // a1 = 1. + 3. + 5.
double a2 = c1.add(<use d2>); // a2 = 2. + 4. + 6.

In Python, I would do this with __getattribute__() like this:

class C:
   def __init__(d1, d2):
      self.d1, self.d2 = d1, d2
      self.other1, self.other2 = None, None
   
   def add(attr):
      return self.c1.__getattribute__(attr) + self.c2.__getattribut__(attr) + self.__getattribute__(attr)

c1 = C(1, 2)
c2 = C(3, 4)
c3 = C(5, 6)

c1.other1 = c2
c1.other2 = c2
a1 = c1.add('d1')
a2 = c1.add('d2')

I feel like I am looking for a kind of pointer-to-member, but can't figure out how to make it work.

Edit, for clarity:

What I have is a Node-class that contains a bunch of properties (temperature, pressure, composition, etc.) and is linked to its neighbouring nodes. I want to be able to use one method to compute for example the interpolation polynomial for a property.

It feels like bad practice to write a dedicated method to interpolate each property, when the math is identical. The same is true for any other mathematical operation that uses a node and its neighbours.

Writing a separate method for each property also reduces scalability, as introducing a new property would require that one also writes new methods to compute gradients, interpolation coefficients, etc. for that property. I would argue that it is definitely cleaner (and less bug-prone) to be able to introduce a new property, and simply call a generic method using a pointer to member.

Upvotes: -1

Views: 135

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 595305

C++ doesn't have reflection, but you can easily accomplish this task by using a std::(unordered_)map, eg:

#include <map> // or <unordered_map>
#include <string>

class C{
public:
    C* linked1;
    C* linked2;

    std::map<std::string, double> values; // or std::unordered_map
    
    C(double d1, double d2) {
        values["d1"] = d1;
        values["d2"] = d2;
    }

    double add(const std::string& name) const {
        return linked1->values.at(name) + linked2->values.at(name) + values.at(name);
    }
};
C c1{1., 2.};
C c2{3., 4.};
C c3{5., 6.};

c1.linked1 = &c2;
c1.linked2 = &c3;

double a1 = c1.add("d1");
double a2 = c1.add("d2"); 

Online Demo

Upvotes: 1

Ranoiaetep
Ranoiaetep

Reputation: 6637

You can't really use a string to get the member without some kind of reflection. However, you can use a pointer to member:

class C {
    double add(double C::* ptr){
        return linked1->*ptr + linked2->*ptr + this->*ptr;
    }
};

Then call it like:

double a1 = c1.add(&C::d1);

Demo

Upvotes: 2

Related Questions