函数同时接受指向成员函数的指针和指向const成员函数的指针

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

本文关键字:函数 成员 指针 const      更新时间:2023-10-16

我有以下代码库:

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)...); }
        // ...
    }
};

当传递指向成员函数(非const)的指针时,此操作有效。但是,如果要传递指向const成员函数的指针,则会导致编译错误,必须复制上述函数才能得到以下代码:

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)...); }
        // ...
    }
};

现在,可以传递const-member-functions和non-const-member-functions。但是,现在,代码是重复的,可维护性降低了。

是否有一种方法可以将这两个函数合并为一个同时接受const-member-functions和non-const-member-functions的函数?

重要提示:我必须将指针函数作为形参(不能使用std::function)

编辑:我已经添加了一些代码。在函数内部,我构建了一个匹配成员函数签名的闭包(相同的返回类型和参数)。该闭包将被存储并在以后用于反射

你可以写一个类型trait,以此来告诉你某个MF是否是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>
                              > { };

并使用它来确保你只得到其中一个:

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)...);
        };
        // ...
    }
};