1

テンプレートをバインドするときに pybind11 の使用を簡素化しようとしています。今のところ、型のパラメーター パックがあり、cl.def()そのパラメーター パックの各型で関数を呼び出す必要があります (以下のコードを参照)。また、名前のベクトルがあり、各名前はパラメーターのパック タイプに対応します。次に例を示します。

#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
 
namespace py {
 
template <typename T>
class class_ {
public:
    template <typename R, typename ...Args>
    class_ & def(char const *, R (T::*)(Args...)) {
        return *this;
    }
};
 
} // py
 
template <typename ...>
struct tl{};
 
template <typename T>
struct type_identity {
    using type = T;
};
 
template <typename T>
static T deduce(type_identity<T>);
 
template <
    typename Apply
  , typename T
  , typename ...Inst
    >
void class_group_def(
    Apply &&func, 
    py::class_<T> & cl, 
    char const * func_name_py, 
    tl<Inst...>)
{
    std::string func_name_py_str(func_name_py);
    remove(func_name_py_str.begin(), func_name_py_str.end(), ' ');    // remove spaces
 
    std::stringstream ss(func_name_py_str);
    std::vector<std::string> func_name_py_str_vec;
    std::string token;
    while (std::getline(ss, token, ';')) {
        func_name_py_str_vec.push_back(token);
    }
 
    for (size_t i = 0; i < sizeof...(Inst); i++){
        // I need to call `cl.def` with every `Inst` corresponding to `func_name_py_str_vec[i]`
        (cl.def(func_name_py_str_vec[i].c_str(), func(type_identity<T>{}, type_identity<Inst>{})),...);
    }
}
 
class A {
public:
    template <typename T>
    void write() { }
};
 
#define CLASS_GROUP_DEF(class_name, func_name_c, func_name_py, ...) \
    class_group_def( \
      [](auto f1, auto f2) { \
         return &decltype(deduce(f1))::template func_name_c<decltype(deduce(f2))>; \
      } \
     , class_name \
     , #func_name_py \
     , tl<__VA_ARGS__>{} \
     )
 
 
int main() {
    py::class_<A> myClass;
 
    // names are divided by semicolon ;
    CLASS_GROUP_DEF(myClass, write, writeInt;writeChar, int, float);
}

for ループでは、型を反復処理する必要があると思います。この関数を 2 つの型 ( intand float) だけで呼び出すと、ループは次のようにアンラップされる可能性があります (このコード スニペットは、私が達成しようとしていることを説明することを目的としています)。

cl.def(func_name_py_str_vec[0].c_str(), func(type_identity<T>{}, type_identity<Inst[0]>{}));
cl.def(func_name_py_str_vec[1].c_str(), func(type_identity<T>{}, type_identity<Inst[1]>{}));

私のタスクを解決する方法はありますか (つまり、パラメーター パックの要素を、それぞれに対応する他の変数と一緒に渡します)?

4

1 に答える 1

1

これにはマクロを使用しないでください。タイプのリストにアクセスすることは、基本的な部分的な特殊化を使用するとかなり簡単です。

#include <iostream>

// This will only ever be used for Visitor<> because of the next specialization.
// So it serves as the "recursion" stop condition.
template<typename... Ts>
struct Visitor {
    template<typename T>
    static void visit(T& v) {}
};

// This will match any type list with at least one type.
template<typename First, typename... Rest>
struct Visitor<First, Rest...> {
  template<typename T>
  static void visit(T& v) {
    // make use of First as the "current" type.
    v.template visit<First>();

    // "recurse" for the rest of the types
    Visitor<Rest...>::visit(v);
  }
};

struct Handler {
    template<typename T> 
    void visit() {
        std::cout << typeid(T).name() << "\n";
    }
};

int main() {
    Handler handler; 
    Visitor<int, float, char>::visit(handler);
}

フォールド式を使用してそれを行う簡単な方法もおそらくあります。しかし、これは十分に単純で、標準の古い (C++11) バージョンとも互換性があります。

于 2021-05-27T19:23:47.110 に答える