Search code examples
c++c++11templatesvariadic-templatespointer-to-member

Parametrize function at compile time based on user expression


I'm writing a C++11 library in which the user needs to specify a struct to use and the elements to be used (in order). For example:

// Declaration
struct MyData{ double x, y ,z;};
...
// Use
MyClass<MyData, y, x> myobj;
MyData mydata;
myobj.set(mydata);
...

Then, MyClass should generate different functions that iterate through the parameter pack, but considering the parameters as expressions. For that, I declared a class with a parameter pack:

template<class T, class ... G>
class MyClass{
    std::vector<double*> var;
    public:
    Test();
    void set(T const& var_);
 };

And then I can't figure out how to generate the set() function. The behavior should be like the following pseudo-code:

 template<class T, class ... G>
 void Test<T, G...>::set(T const& var_){
 unsigned pos = 0;
 for(unsigned i =0; i < sizeof...(G); i++)
     *var[i] = var_.G(i);
}

Which, in the case of MyClass<MyData,y,x> would generate:

...
*var[0] = var_.y;
*var[1] = var_.x;
...

Solution

  • In seems to me that your looking a way to pass a variadic sequence of pointer to member of structs/classes as template parameter and a way to use they.

    The syntax to pass a variadic sequence of pointer to member of structs/classes as template parameter is the following

    template <typename T, typename U, U T::* ... Ms>
    struct MyClass
     { /* something */ };
    

    but, in your case, you've fixed the U type as double so you can simplify as follows

    template <typename T, double T::* ... Ms>
    struct MyClass
     { /* something */ };
    

    To take the correct values in set() you can make somethings as follows

    void set (T const & v0)
     {
       using unused = int[];
    
       (void)unused { 0, (var.emplace_back(v0.*Ms), 0) ... };
     }
    

    Observe that, to simplify, I've changed your var vector in a vector of doubles, not of pointers to đoubles.

    The following is a full (simplified) example

    #include <vector>
    #include <iostream>
    
    struct MyData
     { double x, y ,z; };
    
    template <typename T, double T::* ... Ms>
    struct MyStruct
     { 
       std::vector<double> var;
    
       void set (T const & v0)
        {
          using unused = int[];
    
          (void)unused { 0, (var.emplace_back(v0.*Ms), 0) ... };
        }
     };
    
    int main ()
     {
       MyData md { 1.0, 2.0, 3.0 };
    
       MyStruct<MyData, &MyData::y, &MyData::x>  ms;
    
       ms.set(md);
    
       for ( auto const & d : ms.var )
          std::cout << d << ' ';
    
       std::cout << std::endl;
    
     }