2

This question is a continuation of an earlier one found at: How to template'ize variable NAMES, not types?

Let's say one has the following code:

struct VAR_TYPE{
public:
    bool is_fixed; 
    double value;      // Numerical value
    std::string name;  // Description of variable (to identify it by name)
    int reference_counter;
    /* ect. */
};

struct NODE{
public:
    VAR_TYPE X, Y, Z;
    /* ect. */
};

class MyClass{
public:
    std::vector <NODE_ptr> node;  // shared ptr, using boost::shared_ptr

    // what I have now
    void set_variable_X(int &i, double &P) { node[i]->X.value = P; }
    void set_variable_Y(int &i, double &P) { node[i]->Y.value = P; } 
    void set_variable_Z(int &i, double &P) { node[i]->Z.value = P; }

    // What I want to replace all 3 members with:
    <class T, class N>
    void set_variable( int &i, double &P, /* ??? */ ) { /* ??? */ }
    /* ect. */
};

I'm not sure what would go in areas where '???' is written. Borrowing pseudocode used in the aforementioned link, I would like to something to the affect of

main(){
    MyClass S;
    double x1, y1, z1;
    int index; 

    // set x1, y1, z1, index

    S.set_variable( index, x1, &MyClass::node::X ); // in essence, what I want
    S.set_variable( index, y1, &MyClass::node::Y );
    S.set_variable( index, z1, &MyClass::node::Z );
};

I've tried a few ideas, but errors run a muck. I think the issues lies with the fact I am using a boost shared pointer and/or std::vector. Anyone have an idea what the problem, and a suitable solution, are? One options I have been working with is (but it does not use the calling convention I identified in the int main() above):

template < class T, class N >
void MyClass::set_reference( int &i, double &P,  
                         T NODE::* MemPtr,
                         N VAR_TYPE::* ValPtr)
{
    *MemPtr[i].*ValPtr.value = P; // doesn't work work
};
Community
  • 1
  • 1

1 Answers1

1

The following does what you seem to want:

#include <string>
#include <vector>
struct VAR_TYPE{
public:
    bool is_fixed; 
    double value;      // Numerical value
    std::string name;  // Description of variable (to identify it by name)
    int reference_counter;
    /* ect. */
};

struct NODE{
public:
    VAR_TYPE X, Y, Z;
    /* ect. */
};

class MyClass{
public:
    std::vector <NODE *> node;  // shared ptr, using boost::shared_ptr

    // what I have now
    void set_variable_X(int &i, double &P) { node[i]->X.value = P; }
    void set_variable_Y(int &i, double &P) { node[i]->Y.value = P; } 
    void set_variable_Z(int &i, double &P) { node[i]->Z.value = P; }

    // What I want to replace all 3 members with:
    void set_variable( int &i, double &P, VAR_TYPE NODE::* ptr ) { (node[i]->*ptr).value = P;}
    /* ect. */
};


main(){
    MyClass S;
    double x1, y1, z1;
    int index; 

    // set x1, y1, z1, index

    S.set_variable( index, x1, &NODE::X ); // in essence, what I want
    S.set_variable( index, y1, &NODE::Y );
    S.set_variable( index, z1, &NODE::Z );
}

Though I don't understand what you mean by "A template to call variables by name". BTW there's no reason whatsoever to pass i and P by reference and you shouldn't do it.

enobayram
  • 4,650
  • 23
  • 36
  • Very nice. I'm going to +1 this once I get enough reps. Is there a way for this to work if `node` is declared as `std::vector node`, where `typedef boost::shared_ptr NODE_ptr`? I noted your comment regarding `i` and `P`. –  Sep 24 '12 at 19:09
  • It will work without modifications in the `std::vector node` case. I've just switched to a raw pointer in order not to introduce any external dependency, in case someone tries to compile. – enobayram Sep 24 '12 at 20:48
  • I can't get it to compile when node is declared as a shared pointer. I'm using gcc 4.5.2. The error I get is `error: no match for ‘operator->*’ in ...`. Though, I can get it to compile if node is declared as a `std::vector node`. –  Sep 24 '12 at 21:03
  • Hmm, it seems that boost people forgot to overload the ->* operator :) The fix is easy, use `((*node[i]).*ptr).value = P;` instead, this way, you use the shared_ptr just for indirection (`*`) and the `.*` operation is called on an actual `NODE &` – enobayram Sep 25 '12 at 04:50
  • 1
    In your opinion, do you think there is a legitimate reason the ->* operator is left out? The solution you provided works, so I am marking this as the answer. I owe you a beer. –  Sep 25 '12 at 16:48
  • It'd be nice to raise beer for every SO question I ask or answer :) I guess it's left out mainly because it's a rarely visited corner of C++ (and that there's a very easy fix). It might also be related to the forwarding problem pre-C++11: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm – enobayram Sep 26 '12 at 04:48