I am trying to create python bindings for some C++ functions using pybind11. The functions are templated but in the python bindings, I need one of the template parameter to be a function argument. Currently the way I have it is a lot of repetition for each template parameter.
enum MyEnum {E1, E2, E3};
template<typename T, MyEnum E>
returnType templFunction(int arg){
<function body>
}
PYBIND11_MODULE(moduleName, m){
m.def("pyFunction1", [](int arg, MyEnum e){
switch(e){
case MyEnum::E1: return templFunction<templParam1, E1>(arg);
case MyEnum::E2: return templFunction<templParam1, E2>(arg);
case MyEnum::E3: return templFunction<templParam1, E3>(arg);
default: throw std::invalid_argument("Unknown enum type ...");
}
});
m.def("pyFunction2", [](int arg, MyEnum e){
switch(e){
case MyEnum::E1: return templFunction<templParam2, E1>(arg);
case MyEnum::E2: return templFunction<templParam2, E2>(arg);
case MyEnum::E3: return templFunction<templParam2, E3>(arg);
default: throw std::invalid_argument("Unknown enum type ...");
}
});
// for template type temlParam3, only E1 and E2 are valid enums
m.def("pyFunction3", [](int arg, MyEnum e){
switch(e){
case MyEnum::E1: return templFunction<templParam3, E1>(arg);
case MyEnum::E2: return templFunction<templParam3, E2>(arg);
default: throw std::invalid_argument("Unknown enum type ...");
}
});
// more specializations like above
};
Is there a good way to maybe make a higher order function so I don't need to have so much repeated code?
I also have other functions with similar signatures and template parameters. So ideally I would like to pass a function handle (or function name) and one of the template parameters to a "meta-function" that can generate specializations based on enum and the given template parameters.
Note: I have a static attribute on each of the template types (templParam1
, templateParam2
, ...) which determine the allowed enum types for that template parameter. For e.g. templParam1::allowedEnumTypes = std::vector<myEnum> { E1, E2, E3 };
You can write
template<typename T, MyEnum... Cases>
return_type switcher(int arg, MyEnum e)
{
return_type r;
bool tests[] = {(e == Cases ? (r = templFunction<T, Cases>(arg), true) : false)...};
for(auto t : tests)
if(t)
return r;
throw std::invalid_argument("Unknown enum type ...");
}
and use as
m.def("pyFunction1", switcher<templParam1, E1, E2, E3>);
m.def("pyFunction2", switcher<templParam2, E1, E2, E3>);
m.def("pyFunction3", switcher<templParam3, E1, E2>);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With