[英]Any way to call a constructor (or any function/method) from data types without going through two templated functions?
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. 我有另一个解决方案涉及基于参数类型的HEAD,TAIL ...的递归继承,但这甚至比这个例子更长。
Also, I think to generalize this to work for normal functions, object methods, and constructors I'd need 3 different versions of this. 另外,我认为将其概括为普通函数,对象方法和构造函数,我需要3个不同版本。 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: 将constexpr值作为类型传递:
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: 得到第n个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: 完成所有这些工作之后,
call_constructor
看起来像这样:
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. 传递给
call
一个目标构造一个T
,另一个调用一个方法,另一个调用自由函数。
One thing turns a list of types to indexes+types then invoke a function becomes one operation. 有一件事将类型列表转换为索引+类型然后调用函数成为一个操作。 Turning indexes+types into args another thing.
将索引+类型转换为args是另一回事。 Turning ctor into a callable another thing.
把ctor变成了另一件可以打电话的人。 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. 以上使用C ++ 14简洁,lambda作为一种风格问题。
Code not compiled (written on phone), so certainly contains typos. 代码没有编译(写在手机上),所以肯定包含错别字。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.