This question might provide an answer to another question I posted recently but I feel that the two questions are sufficiently different (this being more general). Also I do realize there are a few questions out there asking for something similar, e.g.
- Specify template parameters at runtime
- Select template argument at runtime in C++
- How to instantiate c++ template according to runtime input?
- Select template argument at runtime in C++
but I could not find anything on how I could implement this dispatching using a function.
Setup:
#include <vector>
#include <iostream>
template <class T>
size_t length(size_t len) {
std::vector<T> vec(len, 100);
return vec.size();
}
size_t length(size_t type, size_t len) {
switch(type) {
case 0: return length<int>(len);
case 1: return length<double>(len);
default: throw std::runtime_error("error");
}
}
int main () {
std::cout << "length: " << length(0, 4) << "\n";
std::cout << "length: " << length(1, 5) << "\n";
return 0;
}
I would like to write a function dispatch(type, fun, ...)
that implements this switch like
auto dispatch(type, fun, ...) -> decltype(fun<int>(...)) {
switch(type) {
case 0: return fun<int>(...);
case 1: return fun<double>(...);
default: throw std::runtime_error("error");
}
}
So far, I was able to come up with two ways of solving this:
Functor approach:
template <template<typename> class Func, typename ...Ar>
auto dispatch_type(size_t type, Ar&&... rg) ->
decltype(Func<int>()(std::forward<Ar>(rg)...)) {
switch(type) {
case 0: return Func<int>()(std::forward<Ar>(rg)...);
case 1: return Func<double>()(std::forward<Ar>(rg)...);
default: throw std::runtime_error("error");
}
}
template <class T>
struct Length {
size_t operator()(size_t len) {
std::vector<T> vec(len, 100);
return vec.size();
}
};
size_t length(size_t type, size_t len) {
return dispatch_type<Length>(type, len);
}
Using boost::mp11
:
#include <boost/mp11/list.hpp>
#include <boost/mp11/algorithm.hpp>
namespace mp11 = boost::mp11;
using num_types = mp11::mp_list<int, double>;
template <size_t i>
using num_type = mp11::mp_at_c<num_types, i>
template<class F>
inline constexpr
decltype(std::declval<F>()(std::declval<mp11::mp_size_t<0>>()))
with_type(std::size_t i, F && f) {
return mp11::mp_with_index< mp11::mp_size<num_types> >(i,
std::forward<F>(f));
}
size_t length(size_t i, size_t len) {
return with_type(i, [&](auto I) {
std::vector< num_type<I> > vec(len, 100);
return vec.size();
});
}
I am surprised this is so hard to achieve. Conceptually my problem is simple: Given a function template, make sure there exists explicit instantiations for a set of types (known at compile time) and dispatch the appropriate one at run time based on a switch.
What other options in addition to the two proposed ones exists? For my application I'm restricted to C++11, but within the context of this question, < C++17 is fine.
Aucun commentaire:
Enregistrer un commentaire