constructor_caller<int,int,char*>(boxed_data);
template<typename ... CONSTRUCTOR_PARAMETER_TYPES>
static void constructor_caller(BoxedDataType & args) {
T * new_cpp_object = call_constructor_helper<CONSTRUCTOR_PARAMETER_TYPES...>(args,
std::index_sequence_for<CONSTRUCTOR_PARAMETER_TYPES...>());
}
template <typename ...Fs, size_t...ns>
static T * call_constructor_helper(BoxedDataType & args, std::index_sequence<ns...>){
// args contains the boxed parameters and CastToNative unboxes
// the value to a native c++ type
return new T(CastToNative<Fs>()(args[ns])...);
}
I have another solution that involves recursive inheritance based on HEAD, TAIL... of the parameter types, but that's even longer than this example.
Also, I think to generalize this to work for normal functions, object methods, and constructors I'd need 3 different versions of this. Is that correct?
You are doing to much stuff at once.
Pass types as values:
template<class T>struct tag_t{constexpr tag_t(){}; using type=T;};
template<class T>constexpr tag_t<T> tag={};
template<class Tag>using type=typename Tag::type;
Pass constexpr values as types:
template<std::size_t I>
using index_t=std::integral_constant<std::size_t,I>;
template<std::size_t I>
constexpr index_t<I> index={};
Get nth arg:
const auto get_nth_from=[](auto&& src){
return [&src](auto index, auto tag)mutable->decltype(auto){
using F=type<decltype(tag)>;
return CastToNative<F>()(src[index]);
};
};
template<class T>
const auto construct=[](auto&&...args)->T*{
return new T(decltype(args)(args)...);
};
Now write your code operating on a generic function object target.
namespace details {
template<class...Ts, std::size_t...Is, class F, class Get>
decltype(auto) call(std::index_sequence<Is...>, F&& f, Get&& get) {
return std::forward<F>(f)(get(index<Is>, tag<Ts>)...);
}
}
template<class...Ts, class F, class Get>
decltype(auto) call(F&& f, Get&& get) {
return details::call<Ts...>( std::index_sequence_for<Ts>{}, std::forward<F>(f), std::forward<Get>(get) );
}
After all that work, call_constructor
looks like this:
template<class T, class...Ts>
T* call_constructor(BoxedDataType & args){
return call<Ts...>( construct<T>, get_nth_from(args) );
}
or somesuch.
One target passed to call
constructs a T
, another invokes a method, another a free function.
One thing turns a list of types to indexes+types then invoke a function becomes one operation. Turning indexes+types into args another thing. Turning ctor into a callable another thing. Each does one thing, and does it well.
More bulk for one operation, but less code duplication, and new operations are easy.
The above uses C++14 for brevity, and lambdas as a matter of style.
Code not compiled (written on phone), so certainly contains typos.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.