как избежать дублирования кода с использованием константных и неконстантных функций-членов, вводимых в шаблоны - PullRequest
4 голосов
/ 03 октября 2019

при попытке получить подписи функций, когда они вводятся в шаблоны, это довольно просто, просто сделайте следующее:

template <class OutType, class... ArgTypes>
void foo(OutType (*func)(ArgTypes...));

получить нестатическую функцию-член лишь немного сложнее:

template <class OutType, class MemberOf, class... ArgTypes>
void foo(OutType (MemberOf::*func)(ArgTypes...));

// or

template <class OutType, class MemberOf, class... ArgTypes>
void foo(OutType (MemberOf::*func)(ArgTypes...) const);

но как именно вы объединяете два объявления функции выше в одно, когда не имеет значения, является ли метод ввода константным?

1 Ответ

4 голосов
/ 04 октября 2019

К сожалению, наличие или отсутствие const в нестатической функции-члене не является функцией, которую можно вывести отдельно от типа функции, к которому она относится. Поэтому, если вы хотите написать одно объявление шаблона foo, ограниченное принятием указателей на члены (но принимающее как const, так и не const функции-члены), тогда это должно быть:

template <class MemberOf, class F>
void foo(F MemberOf::*func);

Например:

#include <type_traits>

template <class MemberOf, class F>
void foo(F MemberOf::*func) {
    static_assert(std::is_same<F, void(int) const>::value);
}

struct S {
    void bar(int) const {}
};

int main() {
    foo(&S::bar);
}

Вы не можете получить типы аргументов F в этой точке. Вы должны были бы отправить к вспомогательной функции. (Но мы не можем вывести все типы одновременно, а также написать одну декларацию, которая принимает как const, так и не-const. Если это единственное, что вы примете, то извините, это невозможно.) Мы можем сделатьэто примерно так:

template <class T>
struct remove_mf_const;

template <class R, class... Args>
struct remove_mf_const<R(Args...)> {
    using type = R(Args...);
};

template <class R, class... Args>
struct remove_mf_const<R(Args...) const> {
    using type = R(Args...);
};

template <bool is_const, class F, class OutType, class MemberOf, class... ArgTypes>
void foo_helper(F func, OutType (MemberOf::*)(ArgTypes...)) {
    // now you have all the types you need
}

template <class MemberOf, class F>
void foo(F MemberOf::*func) {
    static_assert(std::is_function<F>::value, "func must be a pointer to member function");
    using NonConstF = typename remove_mf_const<F>::type;
    constexpr bool is_const = !std::is_same<F, NonConstF>::value;
    foo_helper<is_const>(func, (NonConstF MemberOf::*)nullptr);
}

Coliru link

...