1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
|