I have a function which takes 3 template parameters : two types and an integer constant (used for Eigen storage requirements). It looks like the following template :
template <typename VertexType, typename IndexType, Eigen::StorageOptions Options>
void my_big_function(/* 3 Eigen parameters depending on template args... */) {
/* Do stuff with matrices... */
}
And since this function needs to be bound to python with multiple template "triplets", I thought this could be a nice use of template parameter packs.
I want to achieve the following :
// binds to python :
// - my_big_function<float, int, ColMajor>(...)
bind_my_big_function<float, int, Eigen::ColMajor>(m); // (1)
// binds to python :
// - my_big_function<float, int, ColMajor>(...)
// - my_big_function<float, int, RowMajor>(...)
// - my_big_function<double, int, RowMajor>(...)
bind_my_big_function<float, int, Eigen::ColMajor, float, int, Eigen::RowMajor, double, int, Eigen::RowMajor>(m); // (2)
Where bind_my_big_function
is simple enough :
template <typename MatVertexType, typename MatIndexType, Eigen::StorageOptions MatOptions, typename...RemainingArgs>
void bind_my_big_function(pybind11::module_& m) {
/* bind function taking MatVertexType, MatIndexType & MatOptions and go onto binding other variants of my_big_function */
}
And while I can definitely produce some code that handles case (1), I cannot figure out how to write code that handles case (2). The closest I got was something like this :
template <typename MatVertexType, typename MatIndexType, Eigen::StorageOptions MatOptions>
void bind_my_big_function(pybind11::module_& m) {
m.def("my_big_function_in_python", &my_big_function<MatVertexType, MatIndexType, MatOptions>, /* python arguments...*/);
}
template <
typename MatVertexType, typename MatIndexType, Eigen::StorageOptions MatOptions,
typename...RemainingArgs, typename = typename std::enable_if_t<sizeof...(RemainingArgs) != 0>
>
void bind_my_big_function(pybind11::module_& m) {
m.def("my_big_function_in_python", &my_big_function<MatVertexType, MatIndexType, MatOptions>, /* python arguments...*/);
bind_my_big_function<RemainingArgs...>(m);
}
Are parameter packs supposed to be used in this way ? Only examples I could find of their use was either :
You can't (yet) capture mixed type (MatVertexType
, MatIndexType
) and non-type (MatOptions
) template parameters in a single pack, since as of C++23 a pack has to be of a single kind: type (typename
/class
), template
, or value (concrete or auto
).
There are a couple of possible solutions:
std::integral_constant<Eigen::StorageOption>
, so that it can be passed inside a type pack alongside the type parameters;template<class MatVertexType, class MatIndexType, Eigen::StorageOption MatOptions> struct MatParameters;
(this is the AOS option);std::tuple
for type packs and std::integer_sequence
(in type space) or std::array
(in value space) for value packs (this is the SOA variant of option 2);