-
Notifications
You must be signed in to change notification settings - Fork 0
/
fctr.cpp
135 lines (103 loc) · 3.39 KB
/
fctr.cpp
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <utility>
void f(int& i) {
++i;
}
void f(std::string& s);
// C++ requires you to type out the same function body three times to
// obtain SFINAE-friendliness and noexcept-correctness. That's
// unacceptable.
#define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__){ return __VA_ARGS__; }
// Second, this solution maintains the noexcept quality of each
// overload of f, be it true or false:
// This way, the wrapper around f doesn’t add a specific behaviour. It
// behaves very much like it was just f we called, except that it
// takes care of the overloading resolution. Which was exactly the
// purpose of the challenge.
// Finally, using decltype(__VA_ARGS__) instead of just decltype(auto)
// helps compile-time evaluations like std::is_invocable figure out
// the type of what the function could be returning, depending on its
// arguments. Indeed such contexts don’t instantiate the body of the
// template function to determine what decltype(auto) resolves
// to. This is useful in SFINAE contexts for example.
// The name of overload sets can be legally used as part of a function
// call - we can use a macro to create a lambda for us that "lifts"
// the overload set into a function object.
#define LIFT(f) [](auto&&... xs) RETURNS(f(::std::forward<decltype(xs)>(xs)...))
/* Double functor trick */
class Employee {
public:
explicit Employee(int i) : id_(i) {}
int getId() const {
return id_;
}
bool operator<(const Employee& other) const {
return this->id_ < other.getId();
}
private:
int id_;
};
struct CompareWithId {
bool operator()(Employee const& employee, int id)
{
return employee.getId() < id;
}
bool operator()(int id, Employee const& employee)
{
return id < employee.getId();
}
};
template <typename B1, typename B2>
struct Merged : B1, B2 {
Merged(B1 b1, B2 b2) : B1(std::move(b1)), B2(std::move(b2)) {}
// Needed here
using B1::operator();
using B2::operator();
};
#if 0
template <typename ... B>
struct Merged2 : B... {
template <typename ... T>
Merged2(T && ... t) : B(std::forward<T>(t))...
{
}
using B::operator()...;
};
// C++17 does not allow constructor to have different parameter packs than struct
template<typename ... >
Merged2(T...) -> Merged2<std::decay_t<T>...>;
#endif
int main() {
const auto l1 = []() {return 4;};
const auto l2 = [](const int i){return i * 10;};
Merged<decltype(l1), decltype(l2)> merged(l1,l2);
std::cout << merged(2) << std::endl;
#if 0
Merged2 merged2(l1, l2, [](const double d) { return d*3.2; },
[i = std::make_unique<int>(5)](char c){} );
#endif
std::set<Employee> employees;
employees.insert(Employee(2));
employees.insert(Employee(43));
employees.insert(Employee(27));
std::set<int> ids;
ids.insert(2);
ids.insert(43);
ids.insert(27);
ids.insert(14);
std::vector<int> idsToClean = std::vector<int>();
std::set_difference(ids.begin(), ids.end(),
employees.begin(), employees.end(),
std::back_inserter(idsToClean),
CompareWithId());
std::cout << idsToClean.size() << std::endl;
std::vector<int> numbers = {1, 2, 3, 4, 5};
// std::for_each(begin(numbers), end(numbers), f);
std::for_each(begin(numbers), end(numbers), LIFT(f));
return 0;
}