Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function taking both pointer to member-function and pointer to const member-function

I have the following code base:

template <typename Type>
class SomeClass {
public:
    template <typename ReturnType, typename... Params>
    void register_function(const std::pair<std::string, ReturnType (Type::*)(Params...)> fct) {
        auto f = [fct](Params... params) -> ReturnType { return (Type().*fct.second)(std::ref(params)...); }
        // ...
    }
};

This works when I pass a pointer to a member-function (non-const). However, if I want to pass a pointer to a const member-function, it results in a compile error and I must duplicate the above function to get this code:

template <typename Type>
class SomeClass {
public:
    template <typename ReturnType, typename... Params>
    void register_function(const std::pair<std::string, ReturnType (Type::*)(Params...)> fct) {
        auto f = [fct](Params... params) -> ReturnType { return (Type().*fct.second)(std::ref(params)...); }
        // ...
    }

    template <typename ReturnType, typename... Params>
    void register_function(const std::pair<std::string, ReturnType (Type::*)(Params...) const> fct) {
        auto f = [fct](Params... params) -> ReturnType { return (Type().*fct.second)(std::ref(params)...); }
        // ...
    }
};

Now, I can pass both const-member-functions and non-const-member-functions. But, now, the code is duplicate and maintainability is reduced.

Is there a way to merge these two functions into a function taking both const-member-functions and non-const-member-functions?

Important note: I must really take a pointer function as parameter (no std::function).

Edit: I've added a little bit more code. Inside the functions, I build a closure matching the member function signature (same return types and params). This closure will be stored and used later for making reflection (more here)

like image 505
Simon Ninon Avatar asked Jul 07 '15 18:07

Simon Ninon


1 Answers

You could write a type trait, based on which will tell you if some MF is a pointer-to-member function on Type:

template <typename C, typename T>
struct is_pointer_to_member_helper : std::false_type { };

template <typename C, typename T>
struct is_pointer_to_member_helper<C, T C::*> : std::is_function<T> { };

template <typename C, typename T>
struct is_pointer_to_member : is_pointer_to_member_helper<C,
                                  std::remove_cv_t<T>
                              > { };

And use it to ensure that you only get one of those:

template <typename Type>
class SomeClass {
public:
    template <typename MF>
    std::enable_if_t<is_pointer_to_member<Type, MF>::value>
    register_function(const std::pair<std::string, MF> fct) 
    {
        auto f = [fct](auto&&... params) {
            return (Type{}.*fct.second)(std::forward<decltype(params)>(params)...);
        };

        // ...
    }
};
like image 64
Barry Avatar answered Sep 18 '22 09:09

Barry