/* * Copyright (c) Facebook, Inc. and its affiliates. * * 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. */ #pragma once #include #include #include #include namespace folly { namespace detail { namespace partial { // helper type to make sure that the templated constructor in Partial does // not accidentally act as copy or move constructor struct PartialConstructFromCallable {}; template class Partial { using Indexes = std::make_index_sequence{}>; template static auto invokeForward(Self&& self, std::index_sequence, Args&&... args) -> decltype(invoke( std::declval().f_, std::get(std::declval().stored_args_)..., std::declval()...)) { return invoke( std::forward(self).f_, std::get(std::forward(self).stored_args_)..., std::forward(args)...); } public: template Partial(PartialConstructFromCallable, Callable&& callable, Args&&... args) : f_(std::forward(callable)), stored_args_(std::forward(args)...) {} template auto operator()(CArgs&&... cargs) & -> decltype(invokeForward( std::declval(), Indexes{}, std::declval()...)) { return invokeForward(*this, Indexes{}, std::forward(cargs)...); } template auto operator()(CArgs&&... cargs) const& -> decltype(invokeForward( std::declval(), Indexes{}, std::declval()...)) { return invokeForward(*this, Indexes{}, std::forward(cargs)...); } template auto operator()(As&&... a) && -> decltype(invokeForward( std::declval(), Indexes{}, std::declval()...)) { return invokeForward(std::move(*this), Indexes{}, std::forward(a)...); } template auto operator()(As&&... as) const&& -> decltype(invokeForward( std::declval(), Indexes{}, std::declval()...)) { return invokeForward(std::move(*this), Indexes{}, std::forward(as)...); } private: // the stored callable F f_; // the stored arguments, these will be forwarded along with the actual // argumnets to the callable above Tuple stored_args_; }; } // namespace partial } // namespace detail /** * Partially applies arguments to a callable * * `partial` takes a callable and zero or more additional arguments and returns * a callable object, which when called with zero or more arguments, will invoke * the original callable with the additional arguments passed to `partial`, * followed by those passed to the call. * * E.g. `partial(Foo, 1, 2)(3)` is equivalent to `Foo(1, 2, 3)`. * * `partial` can be used to bind a class method to an instance: * `partial(&Foo::method, foo_pointer)` returns a callable object that can be * invoked in the same way as `foo_pointer->method`. In case the first * argument in a call to `partial` is a member pointer, the second argument * can be a reference, pointer or any object that can be dereferenced to * an object of type Foo (like `std::shared_ptr` or `std::unique_ptr`). * * `partial` is similar to `std::bind`, but you don't have to use placeholders * to have arguments passed on. Any number of arguments passed to the object * returned by `partial` when called will be added to those passed to `partial` * and passed to the original callable. */ template auto partial(F&& f, Args&&... args) -> detail::partial::Partial< typename std::decay::type, std::tuple::type...>> { return {detail::partial::PartialConstructFromCallable{}, std::forward(f), std::forward(args)...}; } } // namespace folly