Я этот код, который, кажется, работает:
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;
}
Однако, как показано выше, параметры шаблона будут точно такими же.
Помимо создания функции с совершенно другим именем, есть ли удобный способ различать указатели на функции и указатели на функции-члены? Или есть способ во время выполнения определить, какой код запустить?
С 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;
}
Указатель на функцию, не являющуюся членом, в вашем примере будет иметь подпись:
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);