有什么方法可以在不通过两个模板函数的情况下从数据类型调用构造函数(或任何 function/method)?
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])...);
}
我有另一个解决方案,它涉及基于参数类型的 HEAD、TAIL... 的递归继承,但这比这个例子还要长。
此外,我认为要将其概括为适用于普通函数、对象方法和构造函数,我需要它的 3 个不同版本。那是对的吗?
您同时处理了很多事情。
将类型作为值传递:
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;
将 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={};
获取第 n 个参数:
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)...);
};
现在编写在通用函数对象目标上运行的代码。
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) );
}
完成所有工作后,call_constructor
看起来像这样:
template<class T, class...Ts>
T* call_constructor(BoxedDataType & args){
return call<Ts...>( construct<T>, get_nth_from(args) );
}
或类似的东西。
传递给 call
的一个目标构造一个 T
,另一个调用一个方法,另一个调用一个自由函数。
一件事是将类型列表转换为索引+类型,然后调用一个函数成为一个操作。将索引+类型转换为参数是另一回事。将 ctor 变成可调用的另一件事。每个人都做一件事,并且做好。
一次操作体积更大,代码重复更少,新操作更容易。
为了简洁起见,上面使用了 C++14,风格上使用了 lambdas。
代码未编译(写在 phone),因此肯定包含拼写错误。
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])...);
}
我有另一个解决方案,它涉及基于参数类型的 HEAD、TAIL... 的递归继承,但这比这个例子还要长。
此外,我认为要将其概括为适用于普通函数、对象方法和构造函数,我需要它的 3 个不同版本。那是对的吗?
您同时处理了很多事情。
将类型作为值传递:
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;
将 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={};
获取第 n 个参数:
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)...);
};
现在编写在通用函数对象目标上运行的代码。
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) );
}
完成所有工作后,call_constructor
看起来像这样:
template<class T, class...Ts>
T* call_constructor(BoxedDataType & args){
return call<Ts...>( construct<T>, get_nth_from(args) );
}
或类似的东西。
传递给 call
的一个目标构造一个 T
,另一个调用一个方法,另一个调用一个自由函数。
一件事是将类型列表转换为索引+类型,然后调用一个函数成为一个操作。将索引+类型转换为参数是另一回事。将 ctor 变成可调用的另一件事。每个人都做一件事,并且做好。
一次操作体积更大,代码重复更少,新操作更容易。
为了简洁起见,上面使用了 C++14,风格上使用了 lambdas。
代码未编译(写在 phone),因此肯定包含拼写错误。