One option is to use this recipe, based on Tennent's Correspondence Principle. You may apply it to a whole block (surrounded by braces) or to an if
, while
, or for
statement (which create their own scopes).
1. Introduce a lambda and call it
Surround the block in question with:
[&]() {
// original code
}();
Compile the file. Possible errors:
not all control paths return a value. You have an early return. Back up and either Eliminate Early Return/Continue/Break or extract something different.
a break/continue statement may only be used within... You have a break/continue. Back up and either Eliminate Early Return/Continue/Break or extract something different.
Check the new lambda for any return statements. If there are any returns and it's obvious that all code paths return, then add a return statement on the next line after the lambda. If there are any returns and it's not obvious that all code paths return, then back up and either Eliminate Early Return/Continue/Break or try extracting something different.
2. Introduce Variable on the lambda
i.e.
[&]() {
// ...
}();
becomes:
auto Applesauce = [&]() {
// ...
};
Applesauce();
Compile to make sure you didn't typo.
3. Set the return type
Set the return type on the lambda (even if it's void
). In Visual Studio, the tooltip over auto
will tell you the type.
i.e.:
auto Applesauce = [&]() -> SOMETYPE {
// ...
};
Compile to make sure you got the return type correct.
4. Capture explicitly
Replace [&]
with [this]
(or []
in a free function) and compile.
For each error about a variable that must be captured:
- Copy the variable name
- Paste it in to the capture list, prefixed with &
- Repeat until green.
i.e.:
auto Applesauce = [this, &foo]() -> void {
cout << foo;
};
The order of the capture list will influence the order of the parameters of the final function. If you want the parameters in a particular order, now is a good time to reorder the capture list.
5. Convert captures to parameters
For each captured local variable (except this
)
- Go to the definition of the variable
- Copy the variable declaration (e.g. Column* pCol
)
- Paste in to the lambda parameter list
- Make the parameter const and by-reference
- Remove the variable from the capture list
- Pass the variable in to the call
- Compile.
i.e.:
Column* pCol = ...
auto Applesauce = [&pCol]() -> void { cout << pCol->name(); };
Applesauce();
becomes
Column* pCol = ...
auto Applesauce = [](Column*& pCol) -> void { cout << pCol->name(); };
Applesauce(pCol);
6. Convert lambda to function
If this
is captured, use 6A.
If this
is not captured, use 6B.
6A. Convert this-bound lambda to member function
- Cut the lambda statement and paste it outside the current function
- Remove
= [this]
- Copy the signature line
- Add
SomeClass::
- Paste the signature in to the class declaration in a private section.
- Compile
i.e.:
auto SomeClass::Applesauce () const -> void {
// ...
};
6B. Convert non-this Lambda to free function
- Cut the lambda statement and paste it above the current function.
- Remove
= []
- Compile