2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

関数オブジェクトから関数のシグネチャを取得する

Last updated at Posted at 2020-02-10

関数オブジェクトから関数のシグネチャを取得するテンプレートクラスを作ってみました
戻り値、引数や修飾子情報を取れます

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;
}

色々とガバガバです
使いどころもわかりません

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?