summaryrefslogtreecommitdiff
path: root/tiger-compiler/lib/misc/lambda-visitor.hh
diff options
context:
space:
mode:
Diffstat (limited to 'tiger-compiler/lib/misc/lambda-visitor.hh')
-rw-r--r--tiger-compiler/lib/misc/lambda-visitor.hh89
1 files changed, 89 insertions, 0 deletions
diff --git a/tiger-compiler/lib/misc/lambda-visitor.hh b/tiger-compiler/lib/misc/lambda-visitor.hh
new file mode 100644
index 0000000..db0b403
--- /dev/null
+++ b/tiger-compiler/lib/misc/lambda-visitor.hh
@@ -0,0 +1,89 @@
+/**
+ ** \file misc/lambda-visitor.hh
+ ** \brief Declaration of misc::LambdaVisitor.
+ **/
+
+#pragma once
+
+namespace misc
+{
+ /** \brief Allows to build a visitor from lambdas to use with std::visit.
+ **
+ ** This allows to use a syntax such as
+ ** std::visit(
+ ** LambdaVisitor{
+ ** Lambda1,
+ ** Lambda2,
+ ** ...
+ ** }, variant);
+ ** to a call specific lambdas depending on the static type of the variant.
+ **
+ ** For instance, the following code:
+ **
+ ** std::visit(
+ ** LambdaVisitor{
+ ** [](int) { std::cout << "It's an int!\n"; },
+ ** [](std::string) { std::cout << "It's a string!\n"; },
+ ** [](auto) { std::cout << "It's anything else!\n"; },
+ ** }, var);
+ **
+ ** would have the following results for these variants:
+ ** std::variant<int, std::string, char> v1 = 1; // It's an int!
+ ** std::variant<int, std::string, char> v2 = "Tigrou"; // It's a string!
+ ** std::variant<int, std::string, char> v3 = 'a'; // It's anything else!
+ **
+ ** This allows to perform quick and efficient pattern matching on variants'
+ ** static type.
+ **
+ ** The really powerful thing here is that this can be used to match multiple
+ ** variants. For instance the following code:
+ **
+ ** std::visit(
+ ** LambdaVisitor{
+ ** [](int, std::string) { ... },
+ ** [](auto, std::string) { ... },
+ ** [](auto, auto) { ... },
+ ** }, var1, var2);
+ **
+ ** would call the first lambda if var1 is an int and var2 a string, the
+ ** second lambda if var2 is a string and var1 anything else than an int,
+ ** and the third in any other case.
+ **
+ ** Do note that you can have a return value for your lambdas, and have
+ ** something like so:
+ ** int a = std::visit(
+ ** LambdaVisitor{
+ ** ...
+ ** }, var);
+ **
+ **
+ ** Be careful , you must necessarily have a matching lambda for any possible
+ ** values of the variants used as arguments! You won't be able to compile
+ ** otherwise.
+ **/
+ template <class... Ts> struct LambdaVisitor : Ts...
+ {
+ /** C++ actually desugars lambdas to some kind of struct functors.
+ ** For instance, the following lambda could be desugared to the following
+ ** struct:
+ **
+ ** auto f = [](int a) { std::cout << a; }
+ **
+ ** struct {
+ ** auto operator()(int a) {
+ ** std::cout << a;
+ ** }
+ ** } f;
+ **
+ ** We therefore want to access the operator() of every lambda/functor used
+ ** to create the LambdaVisitor.
+ **/
+ using Ts::operator()...;
+ };
+
+ /// Class template argument deduction. This allows to implicitly deduce the
+ /// templated type of the visitor created from the types of the arguments
+ /// it is constructed with, without having to explicitly fill the template.
+ template <class... Ts> LambdaVisitor(Ts...) -> LambdaVisitor<Ts...>;
+
+} // namespace misc