参数打包在 std::tuple<> 中,然后应用
argument packing in std::tuple<> and then applying
我正在为lua
编写绑定引擎。它通过实例化函数模板来工作,该模板将lua
提供的参数收集到std::tuple
中,然后将std::tuple
应用于指向成员函数的指针。下面是一个例子:
template <member_meta_info const* mmi, class C, class R, class ...A>
inline typename std::enable_if<std::is_same<void, R>::value, int>::type
member_stub(lua_State* L)
{
assert(sizeof...(A) + 1 == lua_gettop(L));
static std::tuple<A...> args;
set_args<0, 2>(args, L);
lua_getfield(L, -1, "__instance");
assert(lua_islightuserdata(L, -1));
typedef R (C::*ptr_to_member_type)(A...);
apply_tuple(static_cast<C*>(lua_touserdata(L, -1)),
*static_cast<ptr_to_member_type*>(mmi->ptr_to_member), args);
lua_pushnil(L);
return 1;
}
mmi->ptr_to_member
只是一个void*
指针。set_args
的把戏是从:遍历元组:
template<std::size_t I = 0, std::size_t O = 1, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp)>::type
set_args(std::tuple<Tp...>&, lua_State*)
{
}
template<std::size_t I = 0, std::size_t O = 1, typename... Tp>
inline typename std::enable_if<I != sizeof...(Tp)>::type
set_args(std::tuple<Tp...>& t, lua_State* L)
{
set_arg(L, I + O, std::get<I>(t));
set_args<I + 1, O, Tp...>(t, I);
}
set_arg()
是一组重载函数,用于设置从std::get<>
返回的引用的各种基本类型(如int
, double
,…),例如:
inline void set_arg(lua_State* L, std::size_t i, double& value)
{
assert(lua_isnumber(L, i));
value = lua_tonumber(L, i);
}
apply
技巧改编自:如何将元组扩展为可变模板函数的参数?
#ifndef APPLYTUPLE_HPP
# define APPLYTUPLE_HPP
template<size_t N>
struct Apply {
template<typename F, typename T, typename... A>
static inline auto apply(F&& f, T && t, A &&... a)
-> decltype(Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
))
{
return Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
);
}
template<typename C, typename F, typename T, typename... A>
static inline auto apply(C && c, F && f, T && t, A &&... a)
-> decltype(Apply<N-1>::apply(::std::forward<C>(c),
::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
))
{
return Apply<N-1>::apply(::std::forward<C>(c), ::std::forward<F>(f),
::std::forward<T>(t), ::std::get<N-1>(::std::forward<T>(t)),
::std::forward<A>(a)...
);
}
template<typename C, typename T, typename... A>
static inline C* apply(T && t, A &&... a)
{
return Apply<N-1>::template apply<C>(::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
);
}
};
template<>
struct Apply<0> {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T &&, A &&... a)
->decltype((*::std::forward<F>(f))(::std::forward<A>(a)...))
{
return (*::std::forward<F>(f))(::std::forward<A>(a)...);
}
template<typename C, typename F, typename T, typename... A>
static inline auto apply(C && c, F && f, T &&, A &&... a)
->decltype((::std::forward<C>(c)->*::std::forward<F>(f))(::std::forward<A>(a)...))
{
return (::std::forward<C>(c)->*::std::forward<F>(f))(::std::forward<A>(a)...);
}
template<typename C, typename T, typename... A>
static inline C* apply(T &&, A &&... a)
{
return new C(::std::forward<A>(a)...);
}
};
template<typename F, typename T>
inline auto apply_tuple(F && f, T && t)
->decltype(Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::apply(::std::forward<F>(f), ::std::forward<T>(t)))
{
return Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::apply(::std::forward<F>(f), ::std::forward<T>(t));
}
template<typename C, typename F, typename T>
inline auto apply_tuple(C && c, F && f, T && t)
->decltype(Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::apply(::std::forward<C>(c), ::std::forward<F>(f), ::std::forward<T>(t)))
{
return Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::apply(::std::forward<C>(c), ::std::forward<F>(f), ::std::forward<T>(t));
}
template<typename C, typename T>
inline C* apply_tuple(T && t)
{
return Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::template apply<C>(::std::forward<T>(t));
}
#endif // APPLYTUPLE_HPP
将元组args
应用于指向成员函数。现在回答我的问题。我感到不安的是,对于每个函数调用,我将lua
提供的所有参数复制到std::tuple
中,然后将其应用于指向成员的指针上。当然,复制需要一些开销。有没有可能以某种方式省略抄写?是否存在比std::tuple
更适合复制参数的容器(标准的或其他的)?
我认为使用std::tuple
应该很好,但是您可能想尝试放弃static
并仅在一步中构造它(没有递归)。它可以改进生成的代码,但是我将把它留给您来度量和/或分析它。
#include <cstddef>
// we need a compile-time helper to generate indices
template< std::size_t... Ns >
struct indices
{
typedef indices< Ns..., sizeof...( Ns ) > next;
};
template< std::size_t N >
struct make_indices
{
typedef typename make_indices< N - 1 >::type::next type;
};
template<>
struct make_indices< 0 >
{
typedef indices<> type;
};
// instead of set_arg, provide get_arg:
template< typename T >
T get_arg( lua_State* L, std::size_t N )
{
static_assert( sizeof( T ) == 0, "T not specialized" );
}
// one specialization per type
template<>
inline double get_arg< double >( lua_State* L, std::size_t i )
{
assert(lua_isnumber(L, i));
return lua_tonumber(L, i);
}
// etc.
// now that we have the helpers, we use it to create an impl
// and forward the original call to it.
template< typename... Args, std::size_t... Ns >
void member_stub_impl( lua_State* L, const indices< Ns... >& )
{
// and here's the non-recursive direct initialization
// version of a std::tuple< Args... >, adjust the offset (1) as needed
const std::tuple< Args... > args( get_arg< Args >( L, Ns + 1 )... );
// now use it...
}
// the forwarder providing the indices to the impl
template< typename... Args >
void member_stub( lua_State* L )
{
typedef typename make_indices< sizeof...( Args ) >::type Indices;
return member_stub_impl< Args... >( L, Indices() );
}
EDIT:现在我们已经看到了apply_tuple
,我认为你实际上可以摆脱apply_tuple
和std::tuple
本身。上面的帮助器就位后,它可以归结为:
template <member_meta_info const* mmi, class C, class R, class ...A, std::size_t ...Ns>
inline typename std::enable_if<std::is_same<void, R>::value, int>::type
member_stub_impl(lua_State* L, const indices<Ns...>& )
{
assert(sizeof...(A) + 1 == lua_gettop(L));
lua_getfield(L, -1, "__instance");
assert(lua_islightuserdata(L, -1));
typedef R (C::*ptr_to_member_type)(A...);
C* obj = static_cast<C*>(lua_touserdata(L, -1));
auto func = *static_cast<ptr_to_member_type*>(mmi->ptr_to_member);
// look ma, no std::tuple! ;)
obj->*func( get_arg< A >( L, Ns + 1 )... );
lua_pushnil(L);
return 1;
}
我无法测试它,所以那里可能有一些错字,但我希望它们很容易修复。如果你需要帮助,请告诉我。
相关文章:
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 这是我尝试让用户将值输入到数组中.然后将其隐藏为大量的星号
- boost::asio如何生成多个协同程序,然后加入它们
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- 在std::thread中,joinable()然后join()线程安全吗
- EASTL矢量<向量<int>>连续的
- C++:如何读取分离变量,然后读取向量
- 为什么我的递归函数按降序打印,然后按升序打印?
- 等待整个 omp 块完成,然后再调用第二个函数
- CMake:如何将库 A 链接到库 B,然后将可执行文件链接到库 A
- 如何存储用户输入的所有数据,然后在他们想要查看所有数据时显示它们
- '{'标记之前的预期类名,然后在预声明时无效使用不完整的类型'class class_name'
- 如何使变量从 x 到 y,然后从 y 返回到 x 并始终重复该过程
- 我有一个数组,我想输入一个范围,然后找到范围内所有偶数的总和?
- 如何正确地推回然后遍历堆中对象的向量?
- 我似乎无法为指针分配一个数组,然后更改数组的内容
- 如何在字符串中找到字符,然后在C++中提取其余的字符串
- 首先按给定顺序打印所有数字,然后使用 Array 打印所有字符和其他符号
- 将加密消息从 php 发送到 C++ 应用程序,然后使用 CryptoPP 进行解密