"Modern" C ++: eine Wehklagesitzung mit Wehklagen

Es wird eine lange Textwand mit einer Art zufälliger Gedanken geben. Schlüsselideen:


  1. In C ++ ist die Kompilierungszeit sehr wichtig,
  2. Es ist auch wichtig, die Leistung ohne Optimierungen zu steigern.
  3. Die kognitive Belastung ist noch wichtiger. Ich werde diesen Punkt nicht besonders diskutieren, aber wenn ich mich durch die Programmiersprache dumm fühle, werde ich ihn wahrscheinlich nicht verwenden, geschweige denn lieben. C ++ macht das bei mir ständig .

Eric Nieblers Standard Ranges- Blogbeitrag zu C ++ 20-Bereichen umkreiste kürzlich das gesamte Twitter-Universum, begleitet von einer Reihe nicht so schmeichelhafter Kommentare (gelinde gesagt!) Über den Zustand des modernen C ++.



Auch ich habe beigetragen ( Link ):


Dieses Beispiel für pythagoreische Tripel in C ++ 20-Rängen sieht meiner Meinung nach monströs aus. Und ja, ich verstehe, dass Bereiche nützlich sein können, Projektionen nützlich sein können und so weiter. Das Beispiel ist jedoch gruselig. Warum sollte jemand das brauchen?

Schauen wir uns das alles unter dem Schnitt genauer an.



All dies geriet etwas außer Kontrolle (sogar eine Woche später flogen weiterhin Kommentare in diesen Thread-Baum!).


Jetzt muss ich mich bei Eric entschuldigen, dass er mit seinem Artikel begonnen hat. Mein Schrei von Jaroslawna wird sich hauptsächlich mit dem „allgemeinen Zustand von C ++“ befassen. Eine Handvoll verbitterter Gamedev-Typen stieß vor einem Jahr auf die gleiche Weise auf eine Erklärung von Boost.Geometry , und das Gleiche geschah mit Dutzenden anderer Aspekte des C ++ - Ökosystems.


Aber Sie wissen, Twitter ist nicht der beste Ort für sensible Gespräche usw. usw. Wir müssen den Gedanken hier und jetzt erweitern!


Pythagoreische Tripel im Stil der Ränge C ++ 20


Behalten Sie den vollständigen Beispieltext aus Erics Beitrag :


//     C++20.
//    N  .
#include <iostream>
#include <optional>
#include <ranges>   //   !

using namespace std;

// maybe_view    0  1 
template<Semiregular T>
struct maybe_view : view_interface<maybe_view<T>> {
  maybe_view() = default;
  maybe_view(T t) : data_(std::move(t)) {
  }
  T const *begin() const noexcept {
    return data_ ? &*data_ : nullptr;
  }
  T const *end() const noexcept {
    return data_ ? &*data_ + 1 : nullptr;
  }
private:
  optional<T> data_{};
};

// "for_each"   , 
//       ,
//        .
// (   constrained lambdas  C++20.)
inline constexpr auto for_each =
  []<Range R,
     Iterator I = iterator_t<R>,
     IndirectUnaryInvocable<I> Fun>(R&& r, Fun fun)
        requires Range<indirect_result_t<Fun, I>> {
      return std::forward<R>(r)
        | view::transform(std::move(fun))
        | view::join;
  };

// "yield_if"  bool  , 
//    0  1 .
inline constexpr auto yield_if =
  []<Semiregular T>(bool b, T x) {
    return b ? maybe_view{std::move(x)}
             : maybe_view<T>{};
  };

int main() {
  //     :
  using view::iota;
  auto triples =
    for_each(iota(1), [](int z) {
      return for_each(iota(1, z+1), [=](int x) {
        return for_each(iota(x, z+1), [=](int y) {
          return yield_if(x*x + y*y == z*z,
            make_tuple(x, y, z));
        });
      });
    });

    //   10 
    for(auto triple : triples | view::take(10)) {
      cout << '('
           << get<0>(triple) << ','
           << get<1>(triple) << ','
           << get<2>(triple) << ')' << '\n';
  }
}

, , «Getting Lazy with C++», N :


void printNTriples(int n)
{
    int i = 0;
    for (int z = 1; ; ++z)
        for (int x = 1; x <= z; ++x)
            for (int y = x; y <= z; ++y)
                if (x*x + y*y == z*z) {
                    printf("%d, %d, %d\n", x, y, z);
                    if (++i == n)
                        return;
                }
}

:


, . , , ? , ?

(list comprehensions) . , - , C++ , - Haskell . C++20 , . .


C++


, , C/C++ («» — , «, », ). , :


// simplest.cpp
#include <time.h>
#include <stdio.h>

int main()
{
    clock_t t0 = clock();

    int i = 0;
    for (int z = 1; ; ++z)
        for (int x = 1; x <= z; ++x)
            for (int y = x; y <= z; ++y)
                if (x*x + y*y == z*z) {
                    printf("(%i,%i,%i)\n", x, y, z);
                    if (++i == 100)
                        goto done;
                }
    done:

    clock_t t1 = clock();
    printf("%ims\n", (int)(t1-t0)*1000/CLOCKS_PER_SEC);
    return 0;
}

: clang simplest.cpp -o outsimplest. 0.064 , 8480 , 2 ( : 2018 MacBookPro; Core i9 2.9GHz; — Xcode 10 clang).


(3,4,5)
(6,8,10)
(5,12,13)
(9,12,15)
(8,15,17)
(12,16,20)
(7,24,25)
(15,20,25)
(10,24,26)
...
(65,156,169)
(119,120,169)
(26,168,170)

! , («Debug») ; («Release»): clang simplest.cpp -o outsimplest -O2. 0.071 (8480 ), 0 ( , clock()).


, , . « » ( , «» « » ). , , -, N , .


— , , . :


// simple-reusable.cpp
#include <time.h>
#include <stdio.h>

struct pytriples
{
    pytriples() : x(1), y(1), z(1) {}
    void next()
    {
        do
        {
            if (y <= z)
                ++y;
            else
            {
                if (x <= z)
                    ++x;
                else
                {
                    x = 1;
                    ++z;
                }
                y = x;
            }
        } while (x*x + y*y != z*z);
    }
    int x, y, z;
};

int main()
{
    clock_t t0 = clock();

    pytriples py;
    for (int c = 0; c < 100; ++c)
    {
        py.next();
        printf("(%i,%i,%i)\n", py.x, py.y, py.z);
    }

    clock_t t1 = clock();
    printf("%ims\n", (int)(t1-t0)*1000/CLOCKS_PER_SEC);
    return 0;
}

. 168 , .


pytriples, next() ; , . , .


, , for- , , , . , , ( ), .


C++ - , , , , «» ( «Ranges, Code Quality, and the Future of C++»); ( , C++ ):


generator<std::tuple<int,int,int>> pytriples()
{
    for (int z = 1; ; ++z)
        for (int x = 1; x <= z; ++x)
            for (int y = x; y <= z; ++y)
                if (x*x + y*y == z*z)
                    co_yield std::make_tuple(x, y, z);
}

C++


C++20 ? , :


auto triples =
    for_each(iota(1), [](int z) {
        return for_each(iota(1, z+1), [=](int x) {
            return for_each(iota(x, z+1), [=](int y) {
                return yield_if(x*x + y*y == z*z,
                    make_tuple(x, y, z));
                });
            });
        });

. , , , . , C++ , , C++ (« ? , !») — . return- , , , .


, , .


, , , C++, , :


template<Semiregular T>
struct maybe_view : view_interface<maybe_view<T>> {
  maybe_view() = default;
  maybe_view(T t) : data_(std::move(t)) {
  }
  T const *begin() const noexcept {
    return data_ ? &*data_ : nullptr;
  }
  T const *end() const noexcept {
    return data_ ? &*data_ + 1 : nullptr;
  }
private:
  optional<T> data_{};
};
inline constexpr auto for_each =
  []<Range R,
     Iterator I = iterator_t<R>,
     IndirectUnaryInvocable<I> Fun>(R&& r, Fun fun)
        requires Range<indirect_result_t<Fun, I>> {
      return std::forward<R>(r)
        | view::transform(std::move(fun))
        | view::join;
  };
inline constexpr auto yield_if =
  []<Semiregular T>(bool b, T x) {
    return b ? maybe_view{std::move(x)}
             : maybe_view<T>{};
  };

, - , - , Perl , Brainfuck — , . C++ 20 . , , , .


, , maybe_view, for_each, yield_if — « », ; , … .


« »


:



, , C++, , .


C++20 , , range-v3 ( ), .


// ranges.cpp
#include <time.h>
#include <stdio.h>
#include <range/v3/all.hpp>

using namespace ranges;

int main()
{
    clock_t t0 = clock();

    auto triples = view::for_each(view::ints(1), [](int z) {
        return view::for_each(view::ints(1, z + 1), [=](int x) {
            return view::for_each(view::ints(x, z + 1), [=](int y) {
                return yield_if(x * x + y * y == z * z,
                    std::make_tuple(x, y, z));
            });
        });
    });

    RANGES_FOR(auto triple, triples | view::take(100))
    {
        printf("(%i,%i,%i)\n", std::get<0>(triple), std::get<1>(triple), std::get<2>(triple));
    }

    clock_t t1 = clock();
    printf("%ims\n", (int)(t1-t0)*1000/CLOCKS_PER_SEC);
    return 0;
}

0.4.0 (9232b449e44 22 2018 ), clang ranges.cpp -I. -std=c++17 -lc++ -o outranges. 2.92 , 219 , 300 .


, . (clang ranges.cpp -I. -std=c++17 -lc++ -o outranges -O2) 3.02 , 13976 , 1 . , , .


.


— C++


2.85 , « C++».


, « 3 » — , . CPU . , clang (SQLite) , 220 ? 0.9 . , 5 ?


++ , . ? , - (Chromium, Clang/LLVM, UE4, ). , C++, , , , . , , C++ , , , , .


« » #include, . , C++ /.


range-v3 1.8 , ! , 30 , 102 . « C++» 720 .


/ ! — , . . precompiled header (pch.h : #include <range/v3/all.hpp>, pch.h, PCH: clang -x c++-header pch.h -I. -std=c++17 -o pch.h.pch, pch: clang ranges.cpp -I. -std=c++17 -lc++ -o outranges -include-pch pch.h.pch). 2.24 . , PCH 0.7 . 2.1 , , C++ :(



150 . , 2 3 . , 10 . , ? ?


, , , . ; , ( ). , , , , 10 100 , «». , . , , «» «». , 2 .


, (-O2 clang) « C++»… , , «zero cost abstractions», - . , .


! , , . , . - , . , , .


Arseny Kapoulkine «Optimizing OBJ loader» YouTube, , 10 , STL (). () , STL Microsoft .


, «STL — »; STL, (EASTL libc++ ), - Microsoft STL , « ».


, , ! — «STL », , - . (, STL, , C++, ).



« » C#:


using System;
using System.Diagnostics;
using System.Linq;

class Program
{
    public static void Main()
    {
        var timer = Stopwatch.StartNew();
        var triples =
            from z in Enumerable.Range(1, int.MaxValue)
            from x in Enumerable.Range(1, z)
            from y in Enumerable.Range(x, z)
            where x*x+y*y==z*z
            select (x:x, y:y, z:z);
        foreach (var t in triples.Take(100))
        {
            Console.WriteLine($"({t.x},{t.y},{t.z})");
        }
        timer.Stop();
        Console.WriteLine($"{timer.ElapsedMilliseconds}ms");
    }
}

, . C#:


var triples =
    from z in Enumerable.Range(1, int.MaxValue)
    from x in Enumerable.Range(1, z)
    from y in Enumerable.Range(x, z)
    where x*x+y*y==z*z
    select (x:x, y:y, z:z);

C++:


auto triples = view::for_each(view::ints(1), [](int z) {
    return view::for_each(view::ints(1, z + 1), [=](int x) {
        return view::for_each(view::ints(x, z + 1), [=](int y) {
            return yield_if(x * x + y * y == z * z,
                std::make_tuple(x, y, z));
        });
    });
});

, . ? , C# LINQ :


var triples = Enumerable.Range(1, int.MaxValue)
    .SelectMany(z => Enumerable.Range(1, z), (z, x) => new {z, x})
    .SelectMany(t => Enumerable.Range(t.x, t.z), (t, y) => new {t, y})
    .Where(t => t.t.x * t.t.x + t.y * t.y == t.t.z * t.t.z)
    .Select(t => (x: t.t.x, y: t.y, z: t.t.z));

C#? Mac, Mono ( C#) 5.16 mcs Linq.cs 0.20 . « C#» 0.17 .


, LINQ 0.03 . 3 C++ — 100 !


, ?


, - .


, Unity , « Boost ». , , , - Boost.Asio, , , asio.h <windows.h>, .


STL. , , EASTL — , /, , . - , (unordered_map STL , separate chaining; - ). .


.


, ( , ) , «» C++ , ( ! ). , « » , ( , ! ).


, ( ) , , « » . () , , ‎(ノಥ益ಥ)ノ ┻━┻, «, , ». : «, - ?». : «, !». (, , - ). , C C++, , . ; , « — », — ; .


, C++, . , « — », « , , ».


C++?


. , « , , ». , C++ , , !


- , , C++ «» .


C/C++. , - 16 . Boost, : «, , !». , .


, , Formula 1 . ? . ? . , ? ! 99% , ? .


:


, . « ». , C++ 1) 2) , , , , , . 2.

, , C++ , , . . ( ) . ( EASTL). , C++ , (Jai) (Rust, C#).



, , « » , — . , , , , , , . ; , - , — . !


, - , C++, STL . - , .


, . — .


, , , . , , , , , .


, - , ? «» « », . , ? // — . , «, », .


  • « , , » — !
  • « , , , » — !
  • «, » — !
  • « , , , » — , , .

« , , C++», . , « Boost!» C++, , Boost — - .


, , . C C++ , ( Rust, ). C++, , , , , .


, , — . C++, « » ( - ); - . , ; , . , , - , «C++ — , », , .


, (C++11/14/17) C++ — , , constexpr if , . , , STL ( , ), , , ///… , , , .


. 19-20 C++ Russia 2019. , . — Arno Schödl, CTO Think-Cell, «Text Formatting For a Future Range-Based Standard Library». , ? . , ( ).

Source: https://habr.com/ru/post/de438260/


All Articles