用のバインディング エンジンを作成していlua
ます。関数 tamplate をインスタンス化することによって機能します。これは、によって提供さ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
トリックはから盗まれました:
iterate over tuple :
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()
から返される参照を設定する、さまざまなプリミティブ型 ( int
、など) のオーバーロードされた関数のセットです。たとえば、次のようになります。double
std::get<>
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
提供されるすべての引数を a にコピーしstd::tuple
、それをメンバーへのポインターに適用することに不安を感じています。確かに、コピーにはいくらかのオーバーヘッドが伴います。どういうわけかコピーを省略することはできますか?引数のコピーにより適したコンテナ (標準またはそれ以外) は存在しますかstd::tuple
(つまり、脂肪が少なく、よりトリミングされています)。