سيكون هناك جدار طويل من النص ، مع نوع من الأفكار العشوائية. الأفكار الرئيسية:
- في C ++ ، وقت التجميع مهم للغاية ،
- بناء الأداء دون تحسينات مهم أيضًا ،
- الحمل المعرفي هو أكثر أهمية. لن أناقش هذه النقطة بشكل خاص ، لكن إذا كانت لغة البرمجة تجعلني أشعر بالغباء ، فمن غير المرجح أن أستخدمها ، وأحبها كثيرًا. 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». , ? . , ( ).