雖然之前有看過,不過看過即忘,還是得寫下來
What’s projection
從一個寫到爛的範例開始
1 2 3 4 5 6 7 8
| struct Person { std::string name; int age; }; std::vector<Person> persons; std::sort(begin(persons), end(persons), [](const auto& p1, const auto& p2) { return p1.name < p2.name; });
|
相信這樣的程式碼已經寫到吐了
如果用C++20 Ranges寫的話可以這樣寫
1
| std::ranges::sort(persons, std::ranges::less{}, &Person::name);
|
可以知道我們要比的就是name,而這樣的寫法就叫做Projection
Backport to C++17
其實要backport到更之前的版本也行, 只要有第三方或是自己寫的invoke
然後寫一個projecting_fn functor,compose以下的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| template <typename Function, typename Projection> class projecting_fn { public: projecting_fn(Function function, Projection projection) : m_function{ std::move(function) } , m_projection{ std::move(projection) } { }
template <typename... Args> decltype(auto) operator() (Args&&... args) const { return std::invoke( m_function, std::invoke(m_projection, std::forward<decltype(args)>(args))...); }
private: Function m_function; Projection m_projection; }; std::sort(begin(persons), end(persons), projecting_fn{ std::less{}, &Person::name });
|
Projection and view filter
像這樣的Source Code是無法通過編譯的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| template<typename T> struct LessThan { bool operator()(const T& x){ return x < value; } T value; };
struct Apple { int weight; int size; };
int main() { auto apples = std::vector<Apple>{{1,2}, {2,3}, {3,4}};
auto smallApples = apples | views::filter(LessThan{3}, &Apple::size); }
|
解決方式有兩種
不用Projection也是一種解決方法
1
| apples | views::filter([] (Apple& a) {return a.size < 3;})
|
不過這方式就與本文無關了
Boost HOF
1
| apples | views::filter(hof::proj(&Apple::size, LessThan{3}));
|
這方法就類似上面C++17的projecting_fn
Reference