Commit 78c27314 authored by Kenton Varda's avatar Kenton Varda

Update KJ_BIND_METHOD for C++14.

parent 8f5bb09d
...@@ -48,6 +48,10 @@ struct TestType { ...@@ -48,6 +48,10 @@ struct TestType {
int foo(int a, int b) { int foo(int a, int b) {
return a + b + callCount++; return a + b + callCount++;
} }
int foo(int c) {
return c * 100;
}
}; };
TEST(Function, Method) { TEST(Function, Method) {
...@@ -61,6 +65,9 @@ TEST(Function, Method) { ...@@ -61,6 +65,9 @@ TEST(Function, Method) {
EXPECT_EQ(3, obj.callCount); EXPECT_EQ(3, obj.callCount);
Function<int(int)> f3 = KJ_BIND_METHOD(obj, foo);
EXPECT_EQ(12300, f3(123));
// Bind to a temporary. // Bind to a temporary.
f = KJ_BIND_METHOD(TestType(10), foo); f = KJ_BIND_METHOD(TestType(10), foo);
......
...@@ -252,80 +252,42 @@ private: ...@@ -252,80 +252,42 @@ private:
}; };
}; };
#if 1
namespace _ { // private namespace _ { // private
template <typename T, typename Signature, Signature method> template <typename T, typename Func, typename ConstFunc>
class BoundMethod; class BoundMethod {
template <typename T, typename Return, typename... Params, Return (Decay<T>::*method)(Params...)>
class BoundMethod<T, Return (Decay<T>::*)(Params...), method> {
public: public:
BoundMethod(T&& t): t(kj::fwd<T>(t)) {} BoundMethod(T&& t, Func&& func, ConstFunc&& constFunc)
: t(kj::fwd<T>(t)), func(kj::mv(func)), constFunc(kj::mv(constFunc)) {}
Return operator()(Params&&... params) { template <typename... Params>
return (t.*method)(kj::fwd<Params>(params)...); auto operator()(Params&&... params) {
return func(t, kj::fwd<Params>(params)...);
} }
template <typename... Params>
private: auto operator()(Params&&... params) const {
T t; return constFunc(t, kj::fwd<Params>(params)...);
};
template <typename T, typename Return, typename... Params,
Return (Decay<T>::*method)(Params...) const>
class BoundMethod<T, Return (Decay<T>::*)(Params...) const, method> {
public:
BoundMethod(T&& t): t(kj::fwd<T>(t)) {}
Return operator()(Params&&... params) const {
return (t.*method)(kj::fwd<Params>(params)...);
} }
private: private:
T t; T t;
Func func;
ConstFunc constFunc;
}; };
} // namespace _ (private) template <typename T, typename Func, typename ConstFunc>
BoundMethod<T, Func, ConstFunc> boundMethod(T&& t, Func&& func, ConstFunc&& constFunc) {
return { kj::fwd<T>(t), kj::fwd<Func>(func), kj::fwd<ConstFunc>(constFunc) };
}
#define KJ_BIND_METHOD(obj, method) \ } // namespace _ (private)
::kj::_::BoundMethod<KJ_DECLTYPE_REF(obj), \
decltype(&::kj::Decay<decltype(obj)>::method), \
&::kj::Decay<decltype(obj)>::method>(obj)
// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an
// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will
// contain a copy (by move) of it.
//
// The current implementation requires that the method is not overloaded.
//
// TODO(someday): C++14's generic lambdas may be able to simplify this code considerably, and
// probably make it work with overloaded methods.
#else
// Here's a better implementation of the above that doesn't work with GCC (but does with Clang)
// because it uses a local class with a template method. Sigh. This implementation supports
// overloaded methods.
#define KJ_BIND_METHOD(obj, method) \ #define KJ_BIND_METHOD(obj, method) \
({ \ ::kj::_::boundMethod(obj, \
typedef KJ_DECLTYPE_REF(obj) T; \ [](auto& s, auto&&... p) mutable { return s.method(kj::fwd<decltype(p)>(p)...); }, \
class F { \ [](auto& s, auto&&... p) { return s.method(kj::fwd<decltype(p)>(p)...); })
public: \
inline F(T&& t): t(::kj::fwd<T>(t)) {} \
template <typename... Params> \
auto operator()(Params&&... params) \
-> decltype(::kj::instance<T>().method(::kj::fwd<Params>(params)...)) { \
return t.method(::kj::fwd<Params>(params)...); \
} \
private: \
T t; \
}; \
(F(obj)); \
})
// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an // Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an
// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will // lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will
// contain a copy (by move) of it. // contain a copy (by move) of it. The method is allowed to be overloaded.
#endif
} // namespace kj } // namespace kj
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment