"الحديث" C ++: جلسة الرثاء مع الرثاء

سيكون هناك جدار طويل من النص ، مع نوع من الأفكار العشوائية. الأفكار الرئيسية:


  1. في C ++ ، وقت التجميع مهم للغاية ،
  2. بناء الأداء دون تحسينات مهم أيضًا ،
  3. الحمل المعرفي هو أكثر أهمية. لن أناقش هذه النقطة بشكل خاص ، لكن إذا كانت لغة البرمجة تجعلني أشعر بالغباء ، فمن غير المرجح أن أستخدمها ، وأحبها كثيرًا. C ++ يفعل هذا معي باستمرار .

نشر تدوينات ستاندرد رينجز من Eric Niebler على C ++ 20 نطاقات تويتر بأكملها مؤخرًا ، مصحوبة بمجموعة من التعليقات غير الممتلئة (بعبارة ملطفة!) حول حالة C ++ الحديثة.



حتى لقد ساهمت ( الرابط ):


هذا المثال لثلاث مرات من فيثاغوري في صفوف C ++ 20 ، في رأيي ، يبدو بشعًا. ونعم ، أنا أفهم أن النطاقات يمكن أن تكون مفيدة ، والإسقاطات يمكن أن تكون مفيدة ، وهلم جرا. ومع ذلك ، فإن المثال هو زاحف. لماذا يحتاج أي شخص هذا؟

دعونا نلقي نظرة فاحصة على كل هذا تحت الخفض.



كل هذا خرج عن نطاق السيطرة قليلاً (حتى بعد أسبوع ، استمرت التعليقات في الانتقال إلى شجرة الخيوط هذه!).


الآن ، يجب أن أعتذر لإريك لبدء مقالته ؛ صرخي ياروسلافنا سيكون أساسًا حول "الحالة العامة لـ C ++". واجهت حفنة من رجال gamedev المرتدين قبل عام شرحًا لـ Boost.Geometry بنفس الطريقة تقريبًا ، وحدث نفس الشيء مع العشرات من الجوانب الأخرى للنظام البيئي C ++.


لكنك تعلم أن Twitter ليس هو أفضل مكان للمحادثات الحساسة ، إلخ ، إلخ. سيتعين علينا توسيع الفكر هنا والآن!


فيثاغورس يتضاعف ثلاث مرات في أسلوب الرتب C ++ 20


احتفظ بنص المثال الكامل من مشاركة إريك:


//     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/ar438260/


All Articles