blob: 770e45706b02da7a041f4415bbd387f47f50e1e4 [file] [log] [blame]
Vitaly Bukacbed2062015-08-17 12:54:05 -07001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_BIND_H_
6#define BASE_BIND_H_
7
8#include "base/bind_internal.h"
9#include "base/callback_internal.h"
10
11// -----------------------------------------------------------------------------
12// Usage documentation
13// -----------------------------------------------------------------------------
14//
15// See base/callback.h for documentation.
16//
17//
18// -----------------------------------------------------------------------------
19// Implementation notes
20// -----------------------------------------------------------------------------
21//
22// If you're reading the implementation, before proceeding further, you should
23// read the top comment of base/bind_internal.h for a definition of common
24// terms and concepts.
25//
26// RETURN TYPES
27//
28// Though Bind()'s result is meant to be stored in a Callback<> type, it
29// cannot actually return the exact type without requiring a large amount
30// of extra template specializations. The problem is that in order to
31// discern the correct specialization of Callback<>, Bind would need to
32// unwrap the function signature to determine the signature's arity, and
33// whether or not it is a method.
34//
35// Each unique combination of (arity, function_type, num_prebound) where
36// function_type is one of {function, method, const_method} would require
37// one specialization. We eventually have to do a similar number of
38// specializations anyways in the implementation (see the Invoker<>,
39// classes). However, it is avoidable in Bind if we return the result
40// via an indirection like we do below.
41//
42// TODO(ajwong): We might be able to avoid this now, but need to test.
43//
44// It is possible to move most of the static_assert into BindState<>, but it
45// feels a little nicer to have the asserts here so people do not need to crack
46// open bind_internal.h. On the other hand, it makes Bind() harder to read.
47
48namespace base {
49
Vitaly Bukacbed2062015-08-17 12:54:05 -070050template <typename Functor, typename... Args>
51base::Callback<
52 typename internal::BindState<
53 typename internal::FunctorTraits<Functor>::RunnableType,
54 typename internal::FunctorTraits<Functor>::RunType,
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080055 typename internal::CallbackParamTraits<Args>::StorageType...>
Vitaly Bukacbed2062015-08-17 12:54:05 -070056 ::UnboundRunType>
57Bind(Functor functor, const Args&... args) {
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080058 // Type aliases for how to store and run the functor.
59 using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType;
60 using RunType = typename internal::FunctorTraits<Functor>::RunType;
Vitaly Bukacbed2062015-08-17 12:54:05 -070061
62 // Use RunnableType::RunType instead of RunType above because our
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080063 // checks below for bound references need to know what the actual
Vitaly Bukacbed2062015-08-17 12:54:05 -070064 // functor is going to interpret the argument as.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080065 using BoundRunType = typename RunnableType::RunType;
66
67 using BoundArgs =
68 internal::TakeTypeListItem<sizeof...(Args),
69 internal::ExtractArgs<BoundRunType>>;
Vitaly Bukacbed2062015-08-17 12:54:05 -070070
71 // Do not allow binding a non-const reference parameter. Non-const reference
72 // parameters are disallowed by the Google style guide. Also, binding a
73 // non-const reference parameter can make for subtle bugs because the
74 // invoked function will receive a reference to the stored copy of the
75 // argument and not the original.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080076 static_assert(!internal::HasNonConstReferenceItem<BoundArgs>::value,
77 "do not bind functions with nonconst ref");
Vitaly Bukacbed2062015-08-17 12:54:05 -070078
79 const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
80
81 // For methods, we need to be careful for parameter 1. We do not require
82 // a scoped_refptr because BindState<> itself takes care of AddRef() for
83 // methods. We also disallow binding of an array as the method's target
84 // object.
85 static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080086 "first bound argument to method cannot be array");
Vitaly Bukacbed2062015-08-17 12:54:05 -070087 static_assert(
88 !internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080089 "a parameter is a refcounted type and needs scoped_refptr");
Vitaly Bukacbed2062015-08-17 12:54:05 -070090
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080091 using BindState = internal::BindState<
Vitaly Bukacbed2062015-08-17 12:54:05 -070092 RunnableType, RunType,
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080093 typename internal::CallbackParamTraits<Args>::StorageType...>;
Vitaly Bukacbed2062015-08-17 12:54:05 -070094
95 return Callback<typename BindState::UnboundRunType>(
96 new BindState(internal::MakeRunnable(functor), args...));
97}
98
99} // namespace base
100
101#endif // BASE_BIND_H_