1 /*
2 * Copyright 2018 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef FCP_BASE_MOVE_TO_LAMBDA_H_
18 #define FCP_BASE_MOVE_TO_LAMBDA_H_
19
20 #include <utility>
21
22 namespace fcp {
23
24 /**
25 * Copyable wrapper for a move-only value. See MoveToLambda.
26 * The value is accessible with the * and -> operators.
27 *
28 * You must be careful to avoid accidnetal copies of this type. Copies are
29 * destructive (by design), so accidental copies might lead to using a
30 */
31 template <typename T>
32 class MoveToLambdaWrapper {
33 public:
MoveToLambdaWrapper(T t)34 explicit MoveToLambdaWrapper(T t) : value_(std::move(t)) {}
35
36 // The copy and move constructors are intentionally non-const.
37
MoveToLambdaWrapper(MoveToLambdaWrapper const & other)38 MoveToLambdaWrapper(MoveToLambdaWrapper const& other)
39 : value_(std::move(other.value_)) {}
40
41 MoveToLambdaWrapper& operator=(MoveToLambdaWrapper const& other) {
42 value_ = std::move(other.value_);
43 return *this;
44 }
45
46 // We respect const-ness of the wrapper when dereferencing, so that 'mutable'
47 // is required on the lambda depending on usage of the value; changes
48 // to a captured value persist across calls to the lambda, which is rarely
49 // desired.
50
51 T const& operator*() const & {
52 return value_;
53 }
54
55 T const* operator->() const & {
56 return &value_;
57 }
58
59 T& operator*() & {
60 return value_;
61 }
62
63 T* operator->() & {
64 return &value_;
65 }
66
67 private:
68 mutable T value_;
69 };
70
71 /**
72 * Allows capturing a value into a lambda 'by move', before C++14. This is
73 * implemented by a copyable wrapper, which actually moves its value.
74 *
75 * auto moving = MoveToLambda(value);
76 * DoSometing([moving]{ V const& v = *moving; ... });
77 */
78 template <typename T>
MoveToLambda(T && value)79 MoveToLambdaWrapper<std::remove_reference_t<T>> MoveToLambda(T&& value) {
80 static_assert(
81 std::is_rvalue_reference<T&&>::value,
82 "Expected an rvalue: If the value is copied anyway (to this function), "
83 "you might as well put it in the lambda-capture list directly.");
84 return MoveToLambdaWrapper<std::remove_reference_t<T>>(
85 std::forward<T>(value));
86 }
87
88 } // namespace fcp
89
90 #endif // FCP_BASE_MOVE_TO_LAMBDA_H_
91