天天看點

C++20管道運算符

我們不打算介紹太多,因為它實際屬于c++20最為重要的一個特性ranges的一部分

我們講解一下使用和自己實作的例子即可

标準庫的管道運算符使用

#include <ranges>
#include <iostream>

int main()
{
    auto const ints = { 0,1,2,3,4,5 };
    auto even = [](int i) { return 0 == i % 2; };
    auto square = [](int i) { return i * i; };

    // 組合視圖的“管道”文法:
    for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
        std::cout << i << ' ';
    }

    std::cout << '\n';

    // 傳統的“函數式”組合文法,filter是篩選,然後再用transform篩選
    for (int i : std::views::transform(std::views::filter(ints, even), square)) {
        std::cout << i << ' ';
    }
    endl(std::cout);

    auto f = std::views::transform([](int n) { return n *= n; });
    auto ret = ints | f;//并沒有改變ints,隻是傳回一個序列
    for (auto i : ret) {
        std::cout << i << ' ';
    }
}
           
管道運算符調用的函數并不會改變原來的序列,這一點需要注意。雖然管道運算符相比傳統的函數式看着要更加抽象,但是其實如果你真正的去使用了解,倒也是挺優雅的
#include <iostream>
#include <ranges>
#include <string_view>
#include <vector>
#include<algorithm>
#include <numeric>

int main()
{
    using namespace std::literals;
    const auto bits = { "https:"sv, "//"sv, "cppreference"sv, "."sv, "com"sv };
    for (char const c : bits | std::views::join) std::cout << c;
    std::cout << '\n';

    const std::vector<std::vector<int>> v{ {1,2}, {3,4,5}, {6}, {7,8,9} };
    auto jv = std::ranges::join_view(v);
    for (auto const  e : jv) std::cout << e << ' ';
    std::cout << '\n';
    
    int array[5][5]{ 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 };
    for (int c : array | std::views::join)std::cout << c<<' ';
    std::cout << '\n';

    //預設隻能處理兩層,如果多層,那麼就多join幾次
    int array2[2][2][2]{ 1,2,3,4,5,6,7,8 };
    for (int c : std::ranges::join_view(array2) | std::views::join)std::cout << c << ' ';
    std::cout << '\n';
}
           

1) 表示由從拉平範圍的視圖獲得的序列組成的 view 。

2) 範圍擴充卡對象。對于任何适合的子表達式 e 表達式 views::join(e) 表達式等價于 join_view<views::all_t<decltype((e))>>{e}

自己實作類似的管道運算符

其實我們隻要實作一個operator |即可
template<typename U, typename F>
	requires std::regular_invocable<F, U&>
std::vector<U>& operator | (std::vector<U>& vl, F f) {
	for (auto& i : vl) {
		f(i);
	}
	return vl;
}
           

第二行代碼是标準庫的概念庫,要求F是可調用,U的類型也符合

最後傳回引用則是為了鍊式程式設計

使用如下:

int main() {
	std::vector v{ 1,2,3,4,5 };
	std::function f([](int& i) { i = i * i; });
	std::function f2([](int& i) {i = i + i; });
	std::function f3([](int i) {std::cout << i << ' '; });
	v | f | f2 | f3;
	std::cout << '\n';

	v | [](int& i) { i = i * i; } | [](int i) {std::cout << i << ' '; };

	std::cout << '\n';
	for (auto i : v | [](int& i) {i = i / 10; }) {
		std::cout << i << ' ';
	}
}
           
C++20管道運算符

 多使用即可

如果要對概念庫和管道運算符(屬于範圍庫)有詳細的了解,看下面

概念庫 (C++20) - cppreference.com

C++20管道運算符
https://zh.cppreference.com/w/cpp/concepts範圍庫 (C++20) - cppreference.com
C++20管道運算符
https://zh.cppreference.com/w/cpp/ranges