How get the class (object type) from pointer to method
Asked Answered
C

3

6

I have a pointer to the method:

struct A { int method() { return 0; } };
auto fn = &A::method;

I can get a return type by std::result_of, but how I can get from fn the class owner of the method?

Corazoncorban answered 11/2, 2017 at 11:26 Comment(5)
You can't, there's no such trait in the standard. A compiler would know it, so it should be possible, but there's simply no way to get that information.Towney
template <class ClassType, class ReturnType, class... Args> ClassType foo(ReturnType (ClassType::*)(Args...)); should workDoyon
@Doyon You should write that as an answer.Kathykathye
edited on my phone. too hard to provide a well formed answer.. : |Doyon
Take a look to this question related to p0172r0 paper; it mentions a weird way to split class type from pointer-to-member function.Corrade
B
4

Try this:

template<class T>
struct MethodInfo;

template<class C, class R, class... A>
struct MethodInfo<R(C::*)(A...)> //method pointer
{
    typedef C ClassType;
    typedef R ReturnType;
    typedef std::tuple<A...> ArgsTuple;
};

template<class C, class R, class... A>
struct MethodInfo<R(C::*)(A...) const> : MethodInfo<R(C::*)(A...)> {}; //const method pointer

template<class C, class R, class... A>
struct MethodInfo<R(C::*)(A...) volatile> : MethodInfo<R(C::*)(A...)> {}; //volatile method pointer
Broody answered 11/2, 2017 at 11:51 Comment(1)
You probably need a separate const volatile.Cockalorum
F
6

You can match it using class-template-specialization:

//Primary template
template<typename T> struct ClassOf {};

//Thanks T.C for suggesting leaving out the funtion /^argument
template<typename Return, typename Class>
struct ClassOf<Return (Class::*)>{   using type = Class;    };

//An alias
template< typename T> using ClassOf_t = typename ClassOf<T>::type;

Hence given:

struct A { int method() { return 0; } };
auto fn = &A::method;

We can retrieve the class like:

ClassOf_t<decltype(fn)> a;

Full example Here.

Fairly answered 11/2, 2017 at 11:55 Comment(2)
...or just specialize on F C::* instead of having 48 specializations for every possible function type.Pee
@Pee I missed that. Thanks!!. Editing nowFairly
B
4

Try this:

template<class T>
struct MethodInfo;

template<class C, class R, class... A>
struct MethodInfo<R(C::*)(A...)> //method pointer
{
    typedef C ClassType;
    typedef R ReturnType;
    typedef std::tuple<A...> ArgsTuple;
};

template<class C, class R, class... A>
struct MethodInfo<R(C::*)(A...) const> : MethodInfo<R(C::*)(A...)> {}; //const method pointer

template<class C, class R, class... A>
struct MethodInfo<R(C::*)(A...) volatile> : MethodInfo<R(C::*)(A...)> {}; //volatile method pointer
Broody answered 11/2, 2017 at 11:51 Comment(1)
You probably need a separate const volatile.Cockalorum
O
0

Boost callable traits answer, I like it better than shorter answers here since it is a bit more readable to me, but opinions might differ...

#include<string>
#include<type_traits>
#include<tuple>
#include <boost/callable_traits/args.hpp>

struct S{
    int val=46;
    int get(){
        return val;
    }
    void method(const std::string ){
    }
};

int main(){
    using Ts1 = boost::callable_traits::args_t<decltype(&S::val)>;
    using Ts2 = boost::callable_traits::args_t<decltype(&S::get)>;
    using Ts3 = boost::callable_traits::args_t<decltype(&S::method)>;
    std::remove_cvref_t<std::tuple_element<0,Ts1>::type> s1;
    s1.val++;
    std::remove_cvref_t<std::tuple_element<0,Ts2>::type> s2;
    s2.val++;
    std::remove_cvref_t<std::tuple_element<0,Ts3>::type> s3;
    s3.val++;
}

s1, s2, s3 are all of type S.

Obviously you need to do the logic only once, I did it 3 times to show it works fine for pointer to member, pointer to function that takes 0 arguments, pointer to function that takes 1 argument.

Outsoar answered 16/12, 2021 at 20:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.