遍历类型的参数包
Iterate over parameter pack of types
我试图在绑定模板时简化 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 循环中,我想我需要迭代类型。因为我现在只用两种类型(int
和 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]>{}));
有没有办法解决我的任务(即将参数包中的元素与对应于每个元素的其他变量一起传递)?
不要为此使用宏。使用基本的偏特化访问类型列表非常简单:
#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) 兼容。
我试图在绑定模板时简化 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 循环中,我想我需要迭代类型。因为我现在只用两种类型(int
和 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]>{}));
有没有办法解决我的任务(即将参数包中的元素与对应于每个元素的其他变量一起传递)?
不要为此使用宏。使用基本的偏特化访问类型列表非常简单:
#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) 兼容。