Loading lang_cpp_06_misc...
#include <algorithm> #include <vector>
// make extensive use of generic features template<typename T1, typename T2> inline auto helper_1(const T1 &a, const T2 &it_begin, const T2 &it_end) { T1 result{}; std::for_each(it_begin, it_end, [&](const auto &value) { result+=a*value; }); return result; }
// only rely on hardcoded features inline double helper_2(double a, const double *ptr_begin, const double *ptr_end) { double result=0.0; for(const double *ptr=ptr_begin; ptr!=ptr_end; ++ptr) { result+=a*(*ptr); } return result; }
// perform a computation with the generic helper double use_1(double a, const std::vector<double> &values) { return helper_1(a, cbegin(values), cend(values)); }
// perform the same computation with the hardcoded helper double use_2(double a, const std::vector<double> &values) { return helper_2(a, data(values), data(values)+size(values)); }
use_1(double, std::vector<double, std::allocator<double> > const&): mov rdx, QWORD PTR [rdi+8] mov rax, QWORD PTR [rdi] movapd xmm2, xmm0 pxor xmm0, xmm0 cmp rax, rdx je .L4 .L3: movsd xmm1, QWORD PTR [rax] add rax, 8 cmp rax, rdx mulsd xmm1, xmm2 addsd xmm0, xmm1 jne .L3 rep ret .L4: rep ret
use_2(double, std::vector<double, std::allocator<double> > const&): mov rax, QWORD PTR [rdi] mov rdx, QWORD PTR [rdi+8] movapd xmm2, xmm0 pxor xmm0, xmm0 cmp rdx, rax je .L10 .L9: movsd xmm1, QWORD PTR [rax] add rax, 8 cmp rax, rdx mulsd xmm1, xmm2 addsd xmm0, xmm1 jne .L9 rep ret .L10: rep ret
#include <iostream>
int fact(int n) { return n<=1 ? 1 : fact(n-1)*n; }
#if 1 // enable unit tests
# define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN # include "doctest.h" TEST_CASE("testing the factorial function") { CHECK(fact(0) == 1); CHECK(fact(1) == 123); // should fail CHECK(fact(2) == 2); CHECK(fact(3) == 6); CHECK(fact(10) == 3628800); }
#else // produce a usual program
int main() { for(int i=1; i<=10; ++i) { std::cout << "fact(" << i << ")=" << fact(i) << '\n'; } return 0; }
#endif
#include "module_A.cpp" #include "module_B.cpp" #include "module_C.cpp" #include "main_program.cpp"
std::vector<std::string>fabrique le code exécutable qui est spécifique à ce type.
<fstream>décrit les types qui sont en rapport avec l'écriture ou la lecture dans des fichiers.
#include <iostream> #include <string> #include <fstream>
void test_output_text_file(std::string filename) { std::ofstream txt_output{filename}; if(!txt_output) { throw std::runtime_error{"Cannot write to "+filename}; } for(int i=0; i<5; ++i) { txt_output << "value " << i << '\n'; } }
value 0 value 1 value 2 value 3 value 4
#include <iostream> #include <string> #include <fstream>
void test_input_text_file(std::string filename) { std::ifstream txt_input{filename}; if(!txt_input) { throw std::runtime_error{"Cannot read from "+filename}; } std::string word; int value; while(txt_input >> word >> value) { std::cout << "word<" << word << "> value<" << value << ">\n"; } }
word<value> value<0> word<value> value<1> word<value> value<2> word<value> value<3> word<value> value<4>
#include <iostream> #include <string> #include <fstream>
void test_output_bin_file(std::string filename) { std::ofstream bin_output{filename, std::ios::binary}; if(!bin_output) { throw std::runtime_error{"Cannot write to "+filename}; } for(int i=0; i<5; ++i) { bin_output.write(reinterpret_cast<const char *>(&i), sizeof(i)); const double d=1.0/(i+1.0); bin_output.write(reinterpret_cast<const char *>(&d), sizeof(d)); } }
#include <iostream> #include <string> #include <fstream>
void test_input_bin_file(std::string filename) { std::ifstream bin_input{filename, std::ios::binary}; if(!bin_input) { throw std::runtime_error{"Cannot read from "+filename}; } int i; double d; while(bin_input.read(reinterpret_cast<char *>(&i), sizeof(i))&& bin_input.read(reinterpret_cast<char *>(&d), sizeof(d))) { std::cout << "i<" << i << "> d<" << d << ">\n"; } }
i<0> d<1> i<1> d<0.5> i<2> d<0.333333> i<3> d<0.25> i<4> d<0.2>
<sstream>en propose une nouvelle déclinaison qui repose sur des chaînes de caractères : l'écriture vers un tel flux complète petit à petit une chaîne et la lecture depuis un tel flux consomme les caractères préalablement fournis dans une chaîne. La rédaction d'une chaîne de caractères à travers un flux repose sur le type std::ostringstream (output-string-stream).
#include <iostream> #include <sstream>
void test_output_string_stream() { std::ostringstream output; for(int i=0; i<5; ++i) { output << "value " << i << '\n'; } std::string content=output.str(); std::cout << "stream content is <" << content << ">\n"; }
stream content is <value 0 value 1 value 2 value 3 value 4 >
#include <iostream> #include <sstream>
void test_input_string_stream() { std::cout << "provide many values per line\n"; for(std::string line; getline(std::cin, line); ) { std::istringstream input{line}; int count=0; for(double value; input >> value; ++count) { std::cout << ' ' << value << '*' << value << '=' << value*value << '\n'; } if(!count) { std::cout << "no values provided on this line\n"; break; } } }
std::ostream & operator<<(std::ostream &output, const MyType &my_data) { // inject into output some pieces of information from my_data return output; }
std::istream & operator>>(std::istream &input, MyType &my_data) { // extract some pieces of information from input to initialise myData return input; }
<time.h>permettait d'obtenir une mesure du temps de manière portable sur toutes les plate-formes.
<chrono>et documentées à partir de cette page https://en.cppreference.com/w/cpp/chrono.
#include <chrono>
double // seconds (1e-6 precision) since 1970/01/01 00:00:00 UTC get_time() { const auto now=std::chrono::system_clock::now().time_since_epoch(); const auto us=std::chrono::duration_cast<std::chrono::microseconds>(now); return 1e-6*double(us.count()); }
const double t0=get_time(); // ... compute something ... const double t1=get_time(); std::cout << t1-t0 << " seconds elapsed\n";
<stdlib.h>sont bien disponibles sur toutes les plate-formes, il subsiste une grande variété dans leur comportement.
<random>et documentées à partir de cette page https://en.cppreference.com/w/cpp/numeric/random.
#include <random> #include <vector> #include <algorithm> // std::shuffle()
//-- create and seed a general purpose random generator -- std::default_random_engine rnd_gen{std::random_device{}()};
//-- create a uniform distribution of integer values in [0;255] -- std::uniform_int_distribution<int> uni_dist{0, 255};
//-- draw a random integer value -- const int guess_that_integer=uni_dist(rnd_gen);
//-- create a normal distribution of real values (mean=7.0, stddev=2.5) -- std::normal_distribution<double> normal_dist{7.0, 2.5};
//-- draw a random real value -- const double guess_that_real=normal_dist(rnd_gen); std::cout << guess_that_integer << ' ' << guess_that_real << '\n';
//-- shuffle a sequence of values -- std::vector<int> seq={0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; std::shuffle(begin(seq), end(seq), rnd_gen); for(const auto &elem: seq) { std::cout << elem << ' '; } std::cout << '\n';
const double x=12.34; const int i1=x; // warning: conversion to 'int' from 'double' may alter its value const int i2{x}; // warning: narrowing conversion of 'x' from 'double' to 'int' inside { } const int i3=(int)x; // OK, but should be avoided (old C style) const int i4=int(x); // OK, the intention is explicit: we build a new value const int i5=static_cast<int>(x); // OK, very explicit and easy to track
variable_with_type_B=static_cast<type_B>(expression_with_type_A); pointer_on_type_A=static_cast<type_A *>(expression_with_type_void_*);
pointer_on_type_B=reinterpret_cast<type_B *>(pointer_on_type_A); reference_on_type_B=reinterpret_cast<type_B &>(reference_on_type_A);
pointer_on_type_A=const_cast<type_A *>(const_pointer_on_type_A); reference_on_type_A=const_cast<type_A &>(const_reference_on_type_A);
if(pointer_on_type_B=dynamic_cast<type_B *>(pointer_on_type_A)) { // pointer_on_type_A is actually pointing to a type_B } reference_on_type_B=dynamic_cast<type_B &>(reference_on_type_A); // throws a std::bad_cast if reference_on_type_A does not reference a type_B
struct MyType { int member;
MyType(float value) : member{int(value)} { }
explicit MyType(std::string txt) : member{std::stoi(txt)} { }
operator float() const { return float(member); }
explicit operator std::string() const { return std::to_string(member); } };
const float f1=12.34f; const std::string s1="456";
const MyType mt_f=f1; // OK, implicit float-->MyType conversion // const MyType mt_s=s1; // error, no implicit std::string-->MyType conversion const MyType mt_s=MyType{s1}; // OK, explicit std::string-->MyType conversion
const float f2=mt_f; // OK, implicit MyType-->float conversion // const std::string s2=mt_s; // error, no implicit MyType-->std::string conversion const std::string s2=std::string(mt_s); // OK, explicit MyType-->std::string conversion
if constexprqui permet d'envisager plusieurs versions du code source selon le résultat d'une expression logique évaluée lors de la compilation.
if constexprest étroitement liée à ce que le compilateur C++ connaît du code source à ce stade de son analyse.