| /* |
| * Copyright 2015 Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * Defines a function folly::applyTuple, which takes a function and a |
| * std::tuple of arguments and calls the function with those |
| * arguments. |
| * |
| * Example: |
| * |
| * int x = folly::applyTuple(std::plus<int>(), std::make_tuple(12, 12)); |
| * ASSERT(x == 24); |
| */ |
| |
| #ifndef FOLLY_APPLYTUPLE_H_ |
| #define FOLLY_APPLYTUPLE_H_ |
| |
| #include <tuple> |
| #include <functional> |
| #include <type_traits> |
| |
| namespace folly { |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| namespace detail { |
| |
| // This is to allow using this with pointers to member functions, |
| // where the first argument in the tuple will be the this pointer. |
| template<class F> F& makeCallable(F& f) { return f; } |
| template<class R, class C, class ...A> |
| auto makeCallable(R (C::*d)(A...)) -> decltype(std::mem_fn(d)) { |
| return std::mem_fn(d); |
| } |
| |
| template<class Tuple> |
| struct DerefSize |
| : std::tuple_size<typename std::remove_reference<Tuple>::type> |
| {}; |
| |
| template<class Tuple, class ...Unpacked> struct ExprDoUnpack { |
| enum { |
| value = sizeof...(Unpacked) < DerefSize<Tuple>::value |
| }; |
| }; |
| |
| template<class Tuple, class ...Unpacked> struct ExprIsUnpacked { |
| enum { |
| value = sizeof...(Unpacked) == DerefSize<Tuple>::value |
| }; |
| }; |
| |
| // CallTuple recursively unpacks tuple arguments so we can forward |
| // them into the function. |
| template<class Ret> |
| struct CallTuple { |
| template<class F, class Tuple, class ...Unpacked> |
| static typename std::enable_if<ExprDoUnpack<Tuple, Unpacked...>::value, |
| Ret |
| >::type call(const F& f, Tuple&& t, Unpacked&&... unp) { |
| typedef typename std::tuple_element< |
| sizeof...(Unpacked), |
| typename std::remove_reference<Tuple>::type |
| >::type ElementType; |
| return CallTuple<Ret>::call(f, std::forward<Tuple>(t), |
| std::forward<Unpacked>(unp)..., |
| std::forward<ElementType>(std::get<sizeof...(Unpacked)>(t)) |
| ); |
| } |
| |
| template<class F, class Tuple, class ...Unpacked> |
| static typename std::enable_if<ExprIsUnpacked<Tuple, Unpacked...>::value, |
| Ret |
| >::type call(const F& f, Tuple&& t, Unpacked&&... unp) { |
| return makeCallable(f)(std::forward<Unpacked>(unp)...); |
| } |
| }; |
| |
| // The point of this meta function is to extract the contents of the |
| // tuple as a parameter pack so we can pass it into std::result_of<>. |
| template<class F, class Args> struct ReturnValue; |
| template<class F, class ...Args> |
| struct ReturnValue<F,std::tuple<Args...>> { |
| typedef typename std::result_of<F (Args...)>::type type; |
| }; |
| |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| template<class Callable, class Tuple> |
| typename detail::ReturnValue< |
| typename std::decay<Callable>::type, |
| typename std::decay<Tuple>::type |
| >::type |
| applyTuple(const Callable& c, Tuple&& t) { |
| typedef typename detail::ReturnValue< |
| typename std::decay<Callable>::type, |
| typename std::decay<Tuple>::type |
| >::type RetT; |
| return detail::CallTuple<RetT>::call(c, std::forward<Tuple>(t)); |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |
| |
| } |
| |
| #endif |