Akan ada dinding teks yang panjang, dengan jenis pikiran acak. Ide-ide kunci:
- Dalam C ++, waktu kompilasi sangat penting,
- Membangun kinerja tanpa optimasi juga penting,
- Beban kognitif bahkan lebih penting. Saya tidak akan membahas hal ini secara khusus, tetapi jika bahasa pemrograman membuat saya merasa bodoh, saya tidak mungkin menggunakannya, apalagi menyukainya. C ++ melakukan ini dengan saya terus-menerus .
Posting blog Eric Niebler tentang Standar Ranges pada rentang C ++ 20 baru-baru ini mengelilingi seluruh dunia twitter, disertai dengan sekelompok komentar yang tidak terlalu menyanjung (dengan kata lain!) Tentang keadaan C ++ modern.

Bahkan saya telah berkontribusi ( tautan ):
Contoh tiga kali lipat Pythagoras di peringkat C ++ 20 ini, menurut saya, terlihat mengerikan. Dan ya, saya mengerti bahwa rentang dapat bermanfaat, proyeksi dapat bermanfaat, dan sebagainya. Namun, contohnya menyeramkan. Mengapa ada yang membutuhkan ini?
Mari kita cermati semua ini di bawah potongan.
Semua ini sedikit di luar kendali (bahkan seminggu kemudian, komentar terus terbang ke pohon utas ini!).
Sekarang, saya harus meminta maaf kepada Eric karena memulai dengan artikelnya; teriakan Yaroslavna saya terutama tentang "kondisi umum C ++". Sejumlah dudes gamedev yang pahit setahun yang lalu berlari ke penjelasan tentang Boost. Geometri dalam banyak cara yang sama, dan hal yang sama terjadi dengan lusinan aspek lain dari ekosistem C ++.
Tapi tahukah Anda, Twitter bukanlah tempat terbaik untuk percakapan sensitif, dll., Dll. Kita harus mengembangkan pemikiran di sini dan sekarang!
Tiga kali lipat Pythagoras dalam gaya peringkat C ++ 20
Simpan teks contoh lengkap dari pos Eric:
// 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». , ? . , ( ).