基于用户表达式在编译时参数化函数

Parametrize function at compile time based on user expression

我正在编写一个 C++11 库,用户需要在其中指定要使用的 struct 和要使用的元素(按顺序)。例如:

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

然后,MyClass 应该生成遍历参数包的不同函数,但将参数视为表达式。为此,我声明了一个带有参数包的 class:

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

然后我不知道如何生成 set() 函数。行为应该类似于以下伪代码:

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

其中,在 MyClass<MyData,y,x> 的情况下会生成:

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

在我看来,您正在寻找一种将可变指针序列作为模板参数传递给 structs/classes 成员的方法,以及一种使用它们的方法。

将指针的可变序列作为模板参数传递给 structs/classes 的成员的语法如下

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

但是,在您的情况下,您已将 U 类型固定为 double,因此您可以简化如下

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

要在 set() 中获取正确的值,您可以按以下方式进行操作

void set (T const & v0)
 {
   using unused = int[];

   (void)unused { 0, (var.emplace_back(v0.*Ms), 0) ... };
 }

请注意,为简化起见,我已将您的 var 向量更改为 double 的向量,而不是指向 đouble 的指针。

下面是一个完整的(简化的)例子

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

 }

另一种方法是让用户指定元组和索引:

struct MyData : std::tuple<double, double, double> {
    enum Names { X, Y, Z }; // Named indexes.
};

template<class T, size_t... Indexes>
class MyClass {
    std::vector<double*> var;
public:
    void set(T const& t) {
        auto unused = { (*var[Indexes] = std::get<Indexes>(t), 1)... };
        static_cast<void>(unused);
    }
};

int main() {
    MyClass<MyData, MyData::X, MyData::Y> myobj;
    MyData mydata;
    myobj.set(mydata);
}