在编译时根据用户表达式参数化函数

时间:2018-02-05 13:48:25

标签: c++ c++11 templates variadic-templates pointer-to-member

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

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

然后,MyClass应生成迭代参数包的不同函数,但将参数视为表达式。为此,我声明了一个带参数包的类:

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

2 个答案:

答案 0 :(得分:3)

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

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

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 s的向量中更改了double向量,而不是指向đouble s的指针。

以下是完整(简化)示例

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

 }

答案 1 :(得分:0)

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

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