関数オブジェクトから関数のシグネチャを取得するテンプレートクラスを作ってみました
戻り値、引数や修飾子情報を取れます
1.シグネチャ取得
FuncSignature.h
template<class _RetType, class... _Args>
struct FuncSignatureAbstract
{
//!<@brief 戻り値の型
using RetType = _RetType;
//!<@brief 引数群の型(tuple型)
using ArgsType = std::tuple<_Args...>;
// インデックス指定の型
template <size_t index>
struct Arg
{
using Type = typename std::tuple_element<index,
std::tuple<_Args...>>::type;
};
//!<@brief 引数の数を取得
static constexpr size_t ArgsLength() { return sizeof...(_Args); }
//!<@brief 引数群のサイズを取得
static constexpr size_t ArgsSize() {
constexpr ArgsType args;
size_t size = 0ULL;
TupleForEach(args, [&size](auto it) {
size += sizeof(decltype(it));
});
return size;
}
//!<@brief 戻り値の型サイズを取得
static constexpr size_t RetTypeSize()
{
return SizeOf<RetType>::GetSize();
}
private:
template<class T>
struct SizeOfDefault {
static constexpr size_t GetSize() { return sizeof(T); }
};
template<class T>
struct SizeOf : SizeOfDefault<T> {};
template<>
struct SizeOf<void>
{
static constexpr size_t GetSize() { return 0; }
};
template<class... Types, typename FuncType>
constexpr void TupleForEach(const std::tuple<Types...>& _tuple, FuncType func)
{
std::apply([&](auto... args) constexpr {
(func(args), ...);
}, _tuple);
}
};
template<class _ClassType, class _RetType, class... _Args>
struct FuncSignatureMemberFunc : public FuncSignatureAbstract<_RetType, _Args...>
{
//!<@brief クラス型
using ClassType = _ClassType;
//!<@brief メンバ関数か
static constexpr bool IsMemberFunc() { return false; }
};
template<typename T>
struct FuncSignatureSignature;
template<class _RetType, class... _ArgsType>
struct FuncSignature<_RetType(*)(_ArgsType...)> :
public Detail::FuncSignatureAbstract<_RetType, _ArgsType...>
{
// 修飾子情報
//!<@brief constか
static constexpr bool IsConst() { return false; }
//!<@brief volatileか
static constexpr bool IsVolatile() { return false; }
//!<@brief メンバ関数か
static constexpr bool IsMemberFunction() { return false; }
};
template<class ClassType, class _RetType, class... _ArgsType>
struct FuncSignature<_RetType(ClassType::*)(_ArgsType...)> :
public Detail::FuncSignatureMemberFunc<ClassType, _RetType, _ArgsType...>
{
// 修飾子情報
//!<@brief constか
static constexpr bool IsConst() { return false; }
//!<@brief volatileか
static constexpr bool IsVolatile() { return false; }
};
template<class ClassType, class _RetType, class... _ArgsType>
struct FuncSignature<_RetType(ClassType::*)(_ArgsType...)const> :
public Detail::FuncSignatureMemberFunc<ClassType, _RetType, _ArgsType...>
{
// 修飾子情報
//!<@brief constか
static constexpr bool IsConst() { return true; }
//!<@brief volatileか
static constexpr bool IsVolatile() { return false; }
};
template<class ClassType, class _RetType, class... _ArgsType>
struct FuncSignature<_RetType(ClassType::*)(_ArgsType...)volatile> :
public Detail::FuncSignatureMemberFunc<ClassType, _RetType, _ArgsType...>
{
// 修飾子情報
//!<@brief constか
static constexpr bool IsConst() { return false; }
//!<@brief volatileか
static constexpr bool IsVolatile() { return true; }
};
template<class ClassType, class _RetType, class... _ArgsType>
struct FuncSignature<_RetType(ClassType::*)(_ArgsType...)const volatile> :
public Detail::FuncSignatureMemberFunc<ClassType, _RetType, _ArgsType...>
{
// 修飾子情報
//!<@brief constか
static constexpr bool IsConst() { return true; }
//!<@brief volatileか
static constexpr bool IsVolatile() { return true; }
};
main.cpp
class Test
{
public:
int Func(int, float)const{return 0}
}
int main()
{
// 引数の数
constexpr auto argsLength = FuncSignature<decltype(&Test::Func)>::ArgsLength();
return 0;
}
2.おまけ
これを使って任意の関数を実行できるクラスも適当に作ってみました
anyFunc
class AnyFunc
{
public:
constexpr AnyFunc()noexcept :
mObjectPtr(nullptr),
mIsConst(false),
mIsVolatile(false),
mIsMemberFunc(false),
mArgsLength(0U),
mArgsSize(0ULL),
mClassSize(0ULL){}
template<class _ClassType, class _RetType, class... _ArgsType>
AnyFunc(_RetType(_ClassType::*objPtr)(_ArgsType...)const):
mObjectPtr(force_cast<void*>(objPtr)),
mIsConst(true),
mIsVolatile(false),
mIsMemberFunc(true),
mArgsLength(GetSignature<decltype(objPtr)>::ArgsLength()),
mArgsSize(GetSignature<decltype(objPtr)>::ArgsSize()),
mClassSize(sizeof(GetSignature<decltype(objPtr)>::ClassType ))
{
}
template<class RetType = void, class ClassType, class... Args>
RetType Invoke(ClassType* classPtr, Args... args) const
{
using ObjPtrType = RetType(ClassType::*)(Args...);
ObjPtrType ptr = force_cast<ObjPtrType>(mObjectPtr);
_wassert(mClassSize == sizeof(ClassType), L"");
_wassert(mArgsLength == GetSignature<decltype(ptr )>::ArgsSize(), L"");
_wassert(mArgsSize == sizeof...(Args), L"");
if constexpr (std::is_same<void, RetType>::value == false)
{
return (classPtr->*ptr)(args...);
}
else
{
(classPtr->*ptr)(args...);
}
}
inline bool IsConst()const { return mIsConst; }
inline bool IsVolatile()const { return mIsVolatile; }
inline bool IsMemberFunc()const { return mIsMemberFunc; }
inline u32 IsArgsLength()const { return mArgsLength; }
private:
//!<@brief オブジェクト
void* mObjectPtr;
//!<@brief const型か
bool mIsConst;
//!<@brief volatile型か
bool mIsVolatile;
//!<@brief メンバ関数か
bool mIsMemberFunc;
//!<@brief 引数の数
u32 mArgsLength;
//!<@brief 引数群のサイズ
size_t mArgsSize;
//!<@brief クラスのサイズ
size_t mClassSize;
};
main.cpp
class Test
{
public:
int Func(int, float)const{return 0}
}
int main()
{
AnyFunc anyFunc(&Test::Func);
anyFunc.Invoke<int>(testObj, 1, 2.0f);
return 0;
}
色々とガバガバです
使いどころもわかりません