Question

I have a function to compute gradient of different variable defined on set of neighbor points. The algorithm is always the same, but depending on what is computed, different member data of the neighbors are accessed, e.g. when computing gradient of velocity, use Node::velocity, when computing gradient of stress, use Node::stress. What is the best way to avoid writing the same function several times?

I had several possibilities in mind:

  1. Pass lambda function (c++0x) or callable object returning that particular member data in question, called like

    gradVelocity=computeGradient(listOfNeighbors,[](const Node& n){ return n.velocity; });
    

    The minus is extra function call at every read.

  2. Template the function based on integer saying what is being computed:

    enum{VAL_VELOCITY=0,VAL_STRESS,VAL_SOMETHING};
    template<int what> computeGradient(const std::list<Node>& neighbors){
        /*loop over neighbors*/
             value=(what==VAL_VELOCITY?neighbor.velocity:((what==VAL_STRESS)?neighbor.stress:neighbor.something);
        /* and so on */
    }
    
    /* called like this */
    gradVelocity=computeGradient<VAL_VELOCITY>(neighbors);
    

    It should be perhaps efficient (hoping compiler will optimize the conditional with constants away in individual instantiations), but readability and maintainability is pretty low.

Some better idea?

Was it helpful?

Solution

Pointer to member is what you need. The type is written as T S::* T is the type of the data member, S is your struct or class. Here is a small example:

#include <iostream>

struct Foo
{
  int a;
  double b;

  Foo(int a, double b)
    : a(a), b(b)
  { }
};

template<typename T, T Foo::* mem>
void print(const Foo& foo)
{
  std::cout << foo.*mem << std::endl;
}

int main()
{
  Foo f(5, 3.14);
  print<int, &Foo::a>(f);
  print<double, &Foo::b>(f);
}

OTHER TIPS

If all of your fields have the same types, it's easy to use pointers to members:

struct Node
{
  double stress;
  double velosity;
};

void foo(Node* pNode, double Node::*pValue)
{
  cout << pNode->*pValue << endl;
}

int main()
{
  Node n1 = { 1, 2 };

  foo(&n1, &Node::stress);
  foo(&n1, &Node::velosity);
}

Update: If not, it's still easy to combine pointers to members with templates:

struct Node
{
  double stress;
  double velosity;
  int dimension;
};

template<class T>
void foo(Node* pNode, T Node::*pValue)
{
  cout << pNode->*pValue << endl;
}

int main()
{
  Node n1 = { 1, 2 };

  foo(&n1, &Node::stress);
  foo(&n1, &Node::velosity);
  foo(&n1, &Node::dimension);
}

I think this is probably the most efficient possible way. It's pretty vivid too.

I am a huge fan of Boost.Fusion, and more specifically, the Boost.Fusion.Map, which let you build a type -> value kind of map.

struct Velocity {};
struct Stress {};

typedef boost::fusion::map<
  std::pair<Velocity, double>,
  std::pair<Stress, int>
> Map;

Map map;

Now, you can access the map with types:

boost::fusion::at_key<Velocity>(map)

returns a reference to a variable of type boost::fusion::result_of::at_key<Velocity, Map>::type

With appropriate wrapping, you get:

extern Velocity const velocity;
extern Stress const stress;

myItem.access(stress) = 3;

And of course, since we are talking templates, no runtime penalty, at all :)

What about inheriting from Node and using virtual access? It would even be possible to use CRTP to avoid the virtual call.

You can combine velocity, stress, something in a single array and access them based on enum index.

struct Node
{
  int attributes[3]; // contains 'velocity', 'stress', 'something';
  enum { VAL_VELOCITY=0, VAL_STRESS, VAL_SOMETHING };
};

Usage:

Node n;
n.attributes[Node::VAL_VELOCITY] = <value>;  // writing 'Node::velocity'
<otherthing> = n.attributes[Node::VAL_SOMETHING]; // reading 'Node::something'

[Note: If you want to keep attributes inside private region then provide getter and setter methods in Node for accessing them.]

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top