C++ - is it possible to extract class and argument types from a member function type in a template?

前端 未结 4 1679
孤独总比滥情好
孤独总比滥情好 2021-02-15 18:19

I would like to wrap member functions that conform to the type \'void (ClassType::Function)(ArgType)\' with a templated class. Later, I want to pass an instance of ClassType to

4条回答
  •  离开以前
    2021-02-15 18:31

    struct MyClass
    {
        MyClass& Move(MyClass& m) { return *this; }
    };
    
    typedef MyClass& (MyClass::*MethodT) (MyClass&);
    
    template< typename T >
    struct ExtractType : std::false_type
    {
    };
    
    template< typename R, typename C, typename A >
    struct ExtractType< R (C::*)(A) >
    {
        typedef C type;
    };
    
    static_assert( std::is_same< ExtractType< MethodT >::type, MyClass >::value, "oops" );
    

    It appears to work in my version of gcc 4.8.
    It works like I mentioned in the comment, its a "back pattern matching" that the compiler does during specialization checks. This is very powerful.
    So you see, we specified some kind of pattern that if the type T respects, it will be decomposed by the compiler into the three subtypes that composes it: R, C, A. Which is return type, class type and argument.

    However you can see that it works with one argument. How to do when we have an undefined number of arguments ?
    Maybe a list of checker classes, or use variadic templates ?

    And frankly in all honesty, I am not even sure this will work with void. I think void is always impossible to place in template, therefore it will result in many versions of this ExtractType class to support all combinations of possible declarations. Or so it seems to me.

    EDIT:

    Ok so I'm giving this away completely randomly, but it seems in C++11 it works much better than I have expected, this is ok on gcc 4.8:

    struct MyClass
    {
    };
    
    typedef int (MyClass::*MethodT) (bool);
    typedef void (MyClass::*VV) ();
    typedef void (MyClass::*IL) (int, long);
    
    template< typename T >
    struct ExtractType : std::false_type
    {
    };
    
    template< typename R, typename C, class...A >
    struct ExtractType< R (C::*)(A...) >
    {
        typedef C type;
        typedef R returntype;
    };
    
    static_assert( std::is_same< ExtractType< MethodT >::type, MyClass >::value, "oops" );
    static_assert( std::is_same< ExtractType< VV >::type, MyClass >::value, "oops" );
    static_assert( std::is_same< ExtractType< IL >::type, MyClass >::value, "oops" );
    
    static_assert( std::is_same< ExtractType< MethodT >::returntype, int >::value, "oops" );
    static_assert( std::is_same< ExtractType< VV >::returntype, void >::value, "oops" );
    static_assert( std::is_same< ExtractType< IL >::returntype, void >::value, "oops" );
    

    The crazy part being that it doesn't mind void in the return type. Of course its C++11 however.

提交回复
热议问题