Skip to content

Instantly share code, notes, and snippets.

@Nnwww
Created November 6, 2015 07:48
Show Gist options
  • Save Nnwww/c64cb9316c6e0782b308 to your computer and use it in GitHub Desktop.
Save Nnwww/c64cb9316c6e0782b308 to your computer and use it in GitHub Desktop.
ジェネリックラムダ「以外」の(戻り値|引数)を推論して返すメタ関数
#include <type_traits>
namespace m_utl
{
template <typename... Types>
struct type_tuple {};
// 関数の型を受け取り、戻り値を推定するメタ関数
// ジェネリックラムダ以外であればこの中の何れかにオーバーロードされる
namespace result_of_function_impl
{
// 関数
template < typename Result, typename ... Args >
auto eval( Result( * )( Args ... ) ) -> Result;
// メンバ関数ポインタ(非const)
template < typename T, typename Result, typename ... Args >
auto eval( Result( T::* )( Args ... ) ) -> Result;
// メンバ関数ポインタ(const)
template < typename T, typename Result, typename ... Args >
auto eval( Result( T::* )( Args ... ) const ) -> Result;
// 関数オブジェクト(非ジェネリックラムダ)
template < typename T, typename FuncType = decltype( &T::operator() ) >
auto eval( T* ) -> decltype( eval( std::declval<FuncType>() ) );
// ジェネリックラムダはテンプレート引数の指定が不可であり、型が定まらないため、実装は見送る
}
// 関数の型を受け取り、引数を型タプルに包んで返すメタ関数
// ジェネリックラムダ以外であればこの中の何れかにオーバーロードされる
namespace args_of_function_impl
{
// 関数
template < typename Result, typename ... Args >
auto eval( Result( * )( Args ... ) ) -> type_tuple<Args...>;
// メンバ関数ポインタ(非const)
template < typename T, typename Result, typename ... Args >
auto eval( Result( T::* )( Args ... ) ) -> type_tuple<Args...>;
// メンバ関数ポインタ(const)
template < typename T, typename Result, typename ... Args >
auto eval( Result( T::* )( Args ... ) const ) -> type_tuple<Args...>;
// 関数オブジェクト(非ジェネリックラムダ)
template < typename T, typename FuncType = decltype( &T::operator() ) >
auto eval( T* ) -> decltype( eval( std::declval<FuncType>() ) );
// ジェネリックラムダはテンプレート引数の指定が不可であり、型が定まらないため、実装は見送る
}
// インターフェースとしてこれつかってね
template < class T >
using res_of_fn = decltype( result_of_function_impl::eval( std::declval<std::remove_pointer_t<T>*>() ) );
template < class T >
using args_of_fn = decltype( args_of_function_impl::eval( std::declval<std::remove_pointer_t<T>*>() ) );
} // m_utl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment