LoginSignup
2
0

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