различие между указателем на функцию и указателем на функцию-член

Я этот код, который, кажется, работает:

template <typename C>
class class_ {
protected:
std::map<std::string, native_function> methods;
public:
template <typename F, F fn>
class_ &method(const std::string &name) {
methods[name] = method_helper<C, F>::template toNative<fn>();
return *this;
}
};

что позволяет:

class_<MyClass>()
.method<decltype(&MyClass::numRows), &MyClass::numRows>("numRows");

Однако я также хотел бы разрешить добавление функций, не являющихся членами, в качестве методов в мой экспортируемый класс. Вопрос в том, что мне нужно другое определение method работать с обычными указателями функций:

template <F, F fn>
class_ &method(const std::string &name) {
methods[name] = function_helper<F>::template toNative<fn>();
return *this;
}

Однако, как показано выше, параметры шаблона будут точно такими же.

Помимо создания функции с совершенно другим именем, есть ли удобный способ различать указатели на функции и указатели на функции-члены? Или есть способ во время выполнения определить, какой код запустить?

1

Решение

С SFINAE:

template<
typename F
, F fn
, typename std::enable_if<
std::is_member_pointer<F>::value
, int
>::type...
>
class_ &method(const std::string &name)
{
methods[name] = method_helper<C, F>::template toNative<fn>();
return *this;
}

template<
typename F
, F fn
, typename std::enable_if<
!std::is_member_pointer<F>::value
, int
>::type...
>
class_ &method(const std::string &name)
{
methods[name] = function_helper<F>::template toNative<fn>();
return *this;
}
2

Другие решения

Указатель на функцию, не являющуюся членом, в вашем примере будет иметь подпись:

template<typename Ret, typename Args...> Ret (*)(Args args...)

и указатель на функцию-член подпись:

template<typename Ret, typename Args...> Ret (C::*)(Args args...)

Это позволяет вам специализироваться на двух подписях:

template <typename F, F fn>
class_ &method(const std::string &name) { return method_impl(name, fn); }

template <typename F>
class_ &method_impl(const std::string &name, F fn)
{
// non-member function variant.
}

template <typename Ret, typename Args...>
class_ &method_impl(const std::string &name, Ret (C::*fn)(Args args...))
{
// member function variant.
}

ПРИМЕЧАНИЕ: если вы измените method_impl в methodВы можете упростить свой API, позволив:

class_<MyClass>().method("numRows", &MyClass::numRows);
0

По вопросам рекламы [email protected]