I am building a library in which users pass in function pointers of any type. I would like the library to determine the function's signature (using function_types), build a fusion vector for the function's arguments, populate the vector with data from a particular source, and then invoke the function using fusion::invoke.
The kicker is that the argument types may not be default constructible. Therefore I need a way of initializing a fusion vector from a source as it is being created.
For example, the following won't work
namespace ft = ::boost::function_types;
namespace bf = ::boost::fusion;
struct non_def_type {
private:
non_def_type();
};
void my_func(non_def_type);
template <typename FPTR>
void my_invoker(FPTR f) {
typedef typename ft::parameter_types<FPTR>::type parameter_types;
typedef typename bf::result_of::as_vector<parameter_types>::type parameter_vector;
parameter_vector params; // error if FPTR contains a parameter_type that is not default-constructible
//
// ... do something to populate params from data source
//
int main() {
my_invoker(my_func);
}
Any idea how I might initialize the fusion vector as it is being created? I feel like there might be a way to transform parameter_types into a version in which each type is wrapped in a default-constructible wrapper, then transform that list into the final boost fusion list while at the same time populating it with data, but I can't seem to get the functors to work. E.g.:
template <typename T>
struct type_wrapper { type_wrapper() {} };
template <typename T>
struct wrap { typedef type_wrapper<T> type; };
// Metafunction to unwrap types, and function to populate data
// (data should never need to be default-constructible)
struct fill {
template <typename SIG> struct result;
template <typename T>
struct result<fill(const type_wrapper<T>&)> {
typedef T type;
};
// Reference type needed for bf::transform_view
template <typename T>
struct result<fill(type_wrapper<T>&)> {
typedef T type;
};
// Non-reference type needed for bf::vector
template <typename T>
struct result<fill(type_wrapper<T>)> {
typedef T type;
};
template <typename T> T
operator()(const type_wrapper<T>&) const {return data_source<T>().pop();}
};
template <typename FPTR>
void my_invoker(FPTR f) {
typedef typename ft::parameter_types<FPTR>::type parameter_types;
// Conversion 1: create a fusion vector with types wrapped in a
// default-constructible wrapper
typedef mpl::transform<parameter_types, wrap<mpl::_1>, mpl::back_inserter<mpl::vector<> > >::type wrapped_parameter_types;
typedef typename bf::result_of::as_vector<wrapped_parameter_types>::type wrapped_parameter_vector;
// Conversion 2: create a fusion vector with the unwrapped types
// that is also populated with the data from the data_source
// (without having to ever default_construct any of the parameter_types)
typedef typename bf::result_of::transform<const wrapped_params, fill>::type params_view;
typedef typename bf::result_of::as_vector<const params_view>::type params_t;
// Finally: invoke the function with arguments
bf::invoke(f, bf::as_vector(bf::transform(params_view(), fill())));
}
I can't seem to get the meta-function calls or the 'fill' metafunction itself quite right, instead getting vast reams of compiler complaints. Am I missing something? Or alternatively, is there a direct way to initialize a fusion vector?
Many thanks,
Vivek