Given the following code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
double a = 1.1; | |
double b = 2.2; | |
[&a, &b](){ | |
std::cout << "a: " << a << " - b: " << b << "\n"; | |
}(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
double a = 1.1; | |
double b = 2.2; | |
class __lambda__ { | |
public: | |
__lambda__(double& a, double& b):a_(a),b_(b) {} | |
void operator()() const { | |
std::cout << "a: " << a_ << " - b: " << b_ << "\n"; | |
} | |
private: | |
const double& a_; | |
const double& b_; | |
} __lambda__{a, b}; | |
__lambda__(); |
Let's imagine we have some pieces of code that we need to execute after a preamble and before a postamble, something like the following:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void PrePost(const std::function<void(void)>& f) { | |
std::cout << "pre\n"; | |
f(); | |
std::cout << "post\n"; | |
} | |
int main() { | |
double a = 1.1; | |
double b = 2.2; | |
double c = 3.3; | |
PrePost( | |
[&a, &b, &c](){ | |
std::cout << a << " " << b << " " << c << "\n"; | |
} | |
); | |
} |
In this case, we can completely dodge the capture and save us some headaches avoiding the heap allocation when the lambda is converted to that std::function, we can make the function template on the lambda and avoid the std::function conversion. And this is what we get
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <typename F> | |
void PrePost(const F& f) { | |
std::cout << "pre\n"; | |
f(); | |
std::cout << "post\n"; | |
} | |
int main() { | |
double a = 1.1; | |
double b = 2.2; | |
double c = 3.3; | |
PrePost( | |
[&a, &b, &c](){ | |
std::cout << a << " " << b << " " << c << "\n"; | |
}); | |
} |
We have another issue now, PrePost function is not generic (even if it seems).
Let's make it generic, as it is indeed doesn't work for example with mutable lambdas, the following code, for instance, does not compile:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <typename F> | |
void PrePost(const F& f) { | |
std::cout << "pre\n"; | |
f(); | |
std::cout << "post\n"; | |
} | |
int main() { | |
double a = 1.1; | |
double b = 2.2; | |
double c = 3.3; | |
PrePost([&a, &b, c]() mutable { | |
c = 4; | |
std::cout << a << " " << b << " " << c << "\n"; | |
}); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <typename F> | |
void PrePost(F&& f) { | |
std::cout << "pre\n"; | |
f(); | |
std::cout << "post\n"; | |
} | |
int main() { | |
double a = 1.1; | |
double b = 2.2; | |
double c = 3.3; | |
PrePost([&a, &b, c]() mutable { | |
c = 4; | |
std::cout << a << " " << b << " " << c << "\n"; | |
}); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Foo { | |
// used when Foo instance is an l-value | |
void operator()() const & { | |
std::cout << "l-value" << "\n"; | |
} | |
// used when Foo isntance is an r-value | |
void operator()() const && { | |
std::cout << "r-value" << "\n"; | |
} | |
}; | |
Foo f; | |
f(); // First operator is used | |
Foo()(); // Second operator is used |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Foo { | |
void operator()() const & { | |
std::cout << "l-value" << "\n"; | |
} | |
void operator()() const && { | |
std::cout << "r-value" << "\n"; | |
} | |
}; | |
PrePost(Foo()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <typename F> | |
void PrePost(F&& f) { | |
std::cout << "pre\n"; | |
std::forward<F>(f)(); | |
std::cout << "post\n"; | |
} |
Avoid the performance hazzard of std::function
Efficient use of lambda expressions