Loading lang_cpp_02_sharing...
//----------------------------------------------------------------------------
#ifndef S4PRC_NOISY_HPP #define S4PRC_NOISY_HPP
#include <iostream> #include <string> #include <vector>
namespace s4prc {
inline std::ostream & operator<<(std::ostream &output, const std::string &s) // display string within quotes { using std::operator<<; output << '"'; if(const auto sz=size(s); sz>20) // prevent from using too much space { output << s.substr(0, 10) << "..." << s.substr(sz-10); } else { output << s; } return output << '"'; }
template<typename E> inline std::ostream & operator<<(std::ostream &output, const std::vector<E> &v) // display vector within braces { output << '{'; if(const auto sz=size(v); sz>4) // prevent from using too much space { output << v[0] << ',' << v[1] << ",...," << v[sz-2] << ',' << v[sz-1]; } else { int count=0; for(const auto &elem: v) { if(count++) { output << ','; } output << elem; } } return output << '}'; }
template<typename T> struct Noisy : T { Noisy() : T{} { std::cout << "construct " << *this << " from nothing\n"; }
Noisy(const T &t) : T{t} { std::cout << "copy-construct " << *this << "\n ... from " << t << '\n'; }
Noisy(T &&t) : T{std::move(t)} { std::cout << "move-construct " << *this << "\n ... from (moved) " << t << '\n'; }
Noisy(const Noisy &n) : T{static_cast<const T &>(n)} { std::cout << "copy-construct " << *this << "\n ... from " << n << '\n'; }
Noisy(Noisy &&n) noexcept : T{std::move(static_cast<T &&>(n))} { std::cout << "move-construct " << *this << "\n ... from (moved) " << n << '\n'; }
Noisy & operator=(const T &t) { T::operator=(t); std::cout << "copy-assign " << *this << "\n ... from " << t << '\n'; return *this; }
Noisy & operator=(T &&t) { T::operator=(std::move(t)); std::cout << "move-assign " << *this << "\n ... from (moved) " << t << '\n'; return *this; }
Noisy & operator=(const Noisy &n) { T::operator=(static_cast<const T &>(n)); std::cout << "copy-assign " << *this << "\n ... from " << n << '\n'; return *this; }
Noisy & operator=(Noisy &&n) noexcept { T::operator=(std::move(static_cast<T &&>(n))); std::cout << "move-assign " << *this << "\n ... from (moved) " << n << '\n'; return *this; }
~Noisy() { std::cout << "destroy " << *this << '\n'; }
friend std::ostream & operator<<(std::ostream &output, const Noisy &n) { return output << "Noisy@" << &n << ":" << static_cast<const T &>(n); } };
} // namespace s4prc
#endif // S4PRC_NOISY_HPP
//----------------------------------------------------------------------------
void test_construct_destroy() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n1; NoisyStr n2{"DATA"}; std::cout << " n1=" << n1 << "\n n2=" << n2 << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
s4prc::Noisy<std::string>afin de faciliter l'écriture répétée de ce type tout au long de cette expérimentation ; cela sera rendu possible grâce à la saisie préalable de la directive :
using NoisyStr = s4prc::Noisy<std::string>;
~~~~ enter test_construct_destroy() ~~~~ construct Noisy@0x7ffd08373350:"" from nothing move-construct Noisy@0x7ffd08373390:"DATA" ... from (moved) "" n1=Noisy@0x7ffd08373350:"" n2=Noisy@0x7ffd08373390:"DATA" ~~~~ leave test_construct_destroy() ~~~~ destroy Noisy@0x7ffd08373390:"DATA" destroy Noisy@0x7ffd08373350:""
"DATA"transmise explicitement à son initialisation✍
"DATA"semble avoir disparu !
void test_copy() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n1; NoisyStr n2{"DATA"}; NoisyStr n3{n2}; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; n1=n3; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; n1=NoisyStr{"NEW DATA"}; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
~~~~ enter test_copy() ~~~~ construct Noisy@0x7ffd08373290:"" from nothing move-construct Noisy@0x7ffd083732d0:"DATA" ... from (moved) "" copy-construct Noisy@0x7ffd08373350:"DATA" ... from Noisy@0x7ffd083732d0:"DATA" n1=Noisy@0x7ffd08373290:"" n2=Noisy@0x7ffd083732d0:"DATA" n3=Noisy@0x7ffd08373350:"DATA" copy-assign Noisy@0x7ffd08373290:"DATA" ... from Noisy@0x7ffd08373350:"DATA" n1=Noisy@0x7ffd08373290:"DATA" n2=Noisy@0x7ffd083732d0:"DATA" n3=Noisy@0x7ffd08373350:"DATA" move-construct Noisy@0x7ffd083733d0:"NEW DATA" ... from (moved) "" move-assign Noisy@0x7ffd08373290:"NEW DATA" ... from (moved) Noisy@0x7ffd083733d0:"" destroy Noisy@0x7ffd083733d0:"" n1=Noisy@0x7ffd08373290:"NEW DATA" n2=Noisy@0x7ffd083732d0:"DATA" n3=Noisy@0x7ffd08373350:"DATA" ~~~~ leave test_copy() ~~~~ destroy Noisy@0x7ffd08373350:"DATA" destroy Noisy@0x7ffd083732d0:"DATA" destroy Noisy@0x7ffd08373290:"NEW DATA"
"DATA") qui lui est transmise.
NoisyStr{"NEW DATA"}crée une nouvelle donnée de type NoisyStr, initialisée à partir de la chaîne spécifiée, mais ne l'associe à aucune variable : il s'agit d'une valeur temporaire✍
y=3*x+5;, tout se passe comme si nous avions écrit
tmp=3*x;puis
y=tmp+5;.
"NEW DATA"✍
"NEW DATA"semble une nouvelle fois avoir disparu !
"NEW DATA"dont elle disposait à sa création !
"DATA"et
"NEW DATA"de type std::string.
void test_move() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n1; NoisyStr n2{"DATA"}; NoisyStr n3{std::move(n2)}; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; n1=std::move(n3); std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; n1=NoisyStr{"NEW DATA"}; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
<utility>.
~~~~ enter test_move() ~~~~ construct Noisy@0x7ffd08373290:"" from nothing move-construct Noisy@0x7ffd083732d0:"DATA" ... from (moved) "" move-construct Noisy@0x7ffd08373350:"DATA" ... from (moved) Noisy@0x7ffd083732d0:"" n1=Noisy@0x7ffd08373290:"" n2=Noisy@0x7ffd083732d0:"" n3=Noisy@0x7ffd08373350:"DATA" move-assign Noisy@0x7ffd08373290:"DATA" ... from (moved) Noisy@0x7ffd08373350:"" n1=Noisy@0x7ffd08373290:"DATA" n2=Noisy@0x7ffd083732d0:"" n3=Noisy@0x7ffd08373350:"" move-construct Noisy@0x7ffd083733d0:"NEW DATA" ... from (moved) "" move-assign Noisy@0x7ffd08373290:"NEW DATA" ... from (moved) Noisy@0x7ffd083733d0:"" destroy Noisy@0x7ffd083733d0:"" n1=Noisy@0x7ffd08373290:"NEW DATA" n2=Noisy@0x7ffd083732d0:"" n3=Noisy@0x7ffd08373350:"" ~~~~ leave test_move() ~~~~ destroy Noisy@0x7ffd08373350:"" destroy Noisy@0x7ffd083732d0:"" destroy Noisy@0x7ffd08373290:"NEW DATA"
Noisy<std::string> produce(std::string msg) { std::cout << "~~~~ enter " << __func__ << "() ~~~~\n"; Noisy<std::string> result{msg+" via "+__func__}; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; return result; }
void test_return() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n{s4prc::produce("Ciao")}; std::cout << " n=" << n << '\n'; n=s4prc::produce("Hi"); std::cout << " n=" << n << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
~~~~ enter test_return() ~~~~ ~~~~ enter produce() ~~~~ move-construct Noisy@0x7ffd08373310:"Ciao via produce" ... from (moved) "" ~~~~ leave produce() ~~~~ n=Noisy@0x7ffd08373310:"Ciao via produce" ~~~~ enter produce() ~~~~ move-construct Noisy@0x7ffd083733d0:"Hi via produce" ... from (moved) "" ~~~~ leave produce() ~~~~ move-assign Noisy@0x7ffd08373310:"Hi via produce" ... from (moved) Noisy@0x7ffd083733d0:"" destroy Noisy@0x7ffd083733d0:"" n=Noisy@0x7ffd08373310:"Hi via produce" ~~~~ leave test_return() ~~~~ destroy Noisy@0x7ffd08373310:"Hi via produce"
s4prc::Noisy<std::string>: soit on s'en contente en l'état comme ce fut le cas lors de la première invocation pour initialiser directement n, soit on réutilise cette nouvelle valeur pour un autre usage comme c'est le cas lors de cette seconde invocation.
void consume(Noisy<std::string> param) { std::cout << "~~~~ " << __func__ << '(' << param << ") ~~~~\n"; }
void test_params() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n{"DATA"}; s4prc::consume(n); std::cout << "...\n"; s4prc::consume(NoisyStr{"TEMPORARY"}); std::cout << "...\n"; s4prc::consume(std::move(n)); std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
~~~~ enter test_params() ~~~~ move-construct Noisy@0x7ffd08373290:"DATA" ... from (moved) "" copy-construct Noisy@0x7ffd08373310:"DATA" ... from Noisy@0x7ffd08373290:"DATA" ~~~~ consume(Noisy@0x7ffd08373310:"DATA") ~~~~ destroy Noisy@0x7ffd08373310:"DATA" ... move-construct Noisy@0x7ffd08373390:"TEMPORARY" ... from (moved) "" ~~~~ consume(Noisy@0x7ffd08373390:"TEMPORARY") ~~~~ destroy Noisy@0x7ffd08373390:"TEMPORARY" ... move-construct Noisy@0x7ffd083733d0:"DATA" ... from (moved) Noisy@0x7ffd08373290:"" ~~~~ consume(Noisy@0x7ffd083733d0:"DATA") ~~~~ destroy Noisy@0x7ffd083733d0:"DATA" ~~~~ leave test_params() ~~~~ destroy Noisy@0x7ffd08373290:""
//----------------------------------------------------------------------------
#ifndef S4PRC_NOISY_HPP #define S4PRC_NOISY_HPP
#include <iostream> #include <string> #include <vector>
namespace s4prc {
inline std::ostream & operator<<(std::ostream &output, const std::string &s) // display string within quotes { using std::operator<<; output << '"'; if(const auto sz=size(s); sz>20) // prevent from using too much space { output << s.substr(0, 10) << "..." << s.substr(sz-10); } else { output << s; } return output << '"'; }
template<typename E> inline std::ostream & operator<<(std::ostream &output, const std::vector<E> &v) // display vector within braces { output << '{'; if(const auto sz=size(v); sz>4) // prevent from using too much space { output << v[0] << ',' << v[1] << ",...," << v[sz-2] << ',' << v[sz-1]; } else { int count=0; for(const auto &elem: v) { if(count++) { output << ','; } output << elem; } } return output << '}'; }
template<typename T> struct Noisy : T { Noisy() : T{} { std::cout << "construct " << *this << " from nothing\n"; }
Noisy(const T &t) : T{t} { std::cout << "copy-construct " << *this << "\n ... from " << t << '\n'; }
Noisy(T &&t) : T{std::move(t)} { std::cout << "move-construct " << *this << "\n ... from (moved) " << t << '\n'; }
Noisy(const Noisy &n) : T{static_cast<const T &>(n)} { std::cout << "copy-construct " << *this << "\n ... from " << n << '\n'; }
Noisy(Noisy &&n) noexcept : T{std::move(static_cast<T &&>(n))} { std::cout << "move-construct " << *this << "\n ... from (moved) " << n << '\n'; }
Noisy & operator=(const T &t) { T::operator=(t); std::cout << "copy-assign " << *this << "\n ... from " << t << '\n'; return *this; }
Noisy & operator=(T &&t) { T::operator=(std::move(t)); std::cout << "move-assign " << *this << "\n ... from (moved) " << t << '\n'; return *this; }
Noisy & operator=(const Noisy &n) { T::operator=(static_cast<const T &>(n)); std::cout << "copy-assign " << *this << "\n ... from " << n << '\n'; return *this; }
Noisy & operator=(Noisy &&n) noexcept { T::operator=(std::move(static_cast<T &&>(n))); std::cout << "move-assign " << *this << "\n ... from (moved) " << n << '\n'; return *this; }
~Noisy() { std::cout << "destroy " << *this << '\n'; }
friend std::ostream & operator<<(std::ostream &output, const Noisy &n) { return output << "Noisy@" << &n << ":" << static_cast<const T &>(n); } };
} // namespace s4prc
#endif // S4PRC_NOISY_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifndef S4PRC_FNCT_CALL_HPP #define S4PRC_FNCT_CALL_HPP
#include "noisy.hpp"
namespace s4prc {
Noisy<std::string> produce(std::string msg);
void consume(Noisy<std::string> param);
} // namespace s4prc
#endif // S4PRC_FNCT_CALL_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include "fnct_call.hpp" #include <iostream>
namespace s4prc {
Noisy<std::string> produce(std::string msg) { std::cout << "~~~~ enter " << __func__ << "() ~~~~\n"; Noisy<std::string> result{msg+" via "+__func__}; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; return result; }
void consume(Noisy<std::string> param) { std::cout << "~~~~ " << __func__ << '(' << param << ") ~~~~\n"; }
} // namespace s4prc
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include <iostream> #include "noisy.hpp" #include "fnct_call.hpp"
using NoisyStr = s4prc::Noisy<std::string>; // ease code writing
void test_construct_destroy() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n1; NoisyStr n2{"DATA"}; std::cout << " n1=" << n1 << "\n n2=" << n2 << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
void test_copy() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n1; NoisyStr n2{"DATA"}; NoisyStr n3{n2}; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; n1=n3; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; n1=NoisyStr{"NEW DATA"}; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
void test_move() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n1; NoisyStr n2{"DATA"}; NoisyStr n3{std::move(n2)}; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; n1=std::move(n3); std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; n1=NoisyStr{"NEW DATA"}; std::cout << " n1=" << n1 << "\n n2=" << n2 << "\n n3=" << n3 << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
void test_return() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n{s4prc::produce("Ciao")}; std::cout << " n=" << n << '\n'; n=s4prc::produce("Hi"); std::cout << " n=" << n << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
void test_params() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; NoisyStr n{"DATA"}; s4prc::consume(n); std::cout << "...\n"; s4prc::consume(NoisyStr{"TEMPORARY"}); std::cout << "...\n"; s4prc::consume(std::move(n)); std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
int main() { test_construct_destroy(); test_copy(); test_move(); test_return(); test_params(); return 0; }
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifndef S4PRC_NOISY_HPP #define S4PRC_NOISY_HPP
#include <iostream> #include <string> #include <vector>
namespace s4prc {
inline std::ostream & operator<<(std::ostream &output, const std::string &s) // display string within quotes { using std::operator<<; output << '"'; if(const auto sz=size(s); sz>20) // prevent from using too much space { output << s.substr(0, 10) << "..." << s.substr(sz-10); } else { output << s; } return output << '"'; }
template<typename E> inline std::ostream & operator<<(std::ostream &output, const std::vector<E> &v) // display vector within braces { output << '{'; if(const auto sz=size(v); sz>4) // prevent from using too much space { output << v[0] << ',' << v[1] << ",...," << v[sz-2] << ',' << v[sz-1]; } else { int count=0; for(const auto &elem: v) { if(count++) { output << ','; } output << elem; } } return output << '}'; }
template<typename T> struct Noisy : T { Noisy() : T{} { std::cout << "construct " << *this << " from nothing\n"; }
Noisy(const T &t) : T{t} { std::cout << "copy-construct " << *this << "\n ... from " << t << '\n'; }
Noisy(T &&t) : T{std::move(t)} { std::cout << "move-construct " << *this << "\n ... from (moved) " << t << '\n'; }
Noisy(const Noisy &n) : T{static_cast<const T &>(n)} { std::cout << "copy-construct " << *this << "\n ... from " << n << '\n'; }
Noisy(Noisy &&n) noexcept : T{std::move(static_cast<T &&>(n))} { std::cout << "move-construct " << *this << "\n ... from (moved) " << n << '\n'; }
Noisy & operator=(const T &t) { T::operator=(t); std::cout << "copy-assign " << *this << "\n ... from " << t << '\n'; return *this; }
Noisy & operator=(T &&t) { T::operator=(std::move(t)); std::cout << "move-assign " << *this << "\n ... from (moved) " << t << '\n'; return *this; }
Noisy & operator=(const Noisy &n) { T::operator=(static_cast<const T &>(n)); std::cout << "copy-assign " << *this << "\n ... from " << n << '\n'; return *this; }
Noisy & operator=(Noisy &&n) noexcept { T::operator=(std::move(static_cast<T &&>(n))); std::cout << "move-assign " << *this << "\n ... from (moved) " << n << '\n'; return *this; }
~Noisy() { std::cout << "destroy " << *this << '\n'; }
friend std::ostream & operator<<(std::ostream &output, const Noisy &n) { return output << "Noisy@" << &n << ":" << static_cast<const T &>(n); } };
} // namespace s4prc
#endif // S4PRC_NOISY_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifndef S4PRC_STR_VEC_HPP #define S4PRC_STR_VEC_HPP
#include "noisy.hpp" #include <tuple>
namespace s4prc {
using StrVec = std::vector<std::string>;
StrVec make_StrVec(int count);
//---- noisy functions ----
Noisy<StrVec> change_by_val(Noisy<StrVec> sv, std::string s, char c);
void change_by_ref(Noisy<StrVec> &sv, std::string s, char c);
std::tuple<Noisy<std::string>, // even strings Noisy<std::string>, // odd strings int> // total length many_results(const Noisy<StrVec> &sv);
//---- silent functions ----
StrVec change_by_val(StrVec sv, std::string s, char c);
void change_by_ref(StrVec &sv, std::string s, char c);
std::tuple<std::string, // even strings std::string, // odd strings int> // total length many_results(const StrVec &sv);
} // namespace s4prc
#endif // S4PRC_STR_VEC_HPP
//----------------------------------------------------------------------------
StrVec make_StrVec(int count) { StrVec result; for(int i=0; i<count; ++i) { result.emplace_back("str"+std::to_string(i)); } return result; }
<string>fournit une chaîne de caractères représentant la valeur numérique passée en paramètre.
void test_noisy() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; s4prc::Noisy<s4prc::StrVec> big=s4prc::make_StrVec(10'000); std::cout << ">>> big=" << big << '\n'; std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
s4prc::Noisy<s4prc::StrVec>initialisée par un appel à s4prc::make_Strvec() réclamant 10'000✍
<<) existant déjà dans l'espace de noms std.
Noisy<StrVec>.
Noisy<StrVec> change_by_val(Noisy<StrVec> sv, std::string s, char c) { std::cout << "~~~~ enter " << __func__ << "() ~~~~\n"; sv.emplace_back(std::move(s)); for(auto &elem: sv) { elem+=c; } std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; return sv; }
... big=s4prc::change_by_val(big, std::to_string(size(big))+'!', 'A'); std::cout << ">>> big=" << big << '\n'; ...
<string>fournit une chaîne de caractères représentant la valeur numérique passée en paramètre.
... big=s4prc::change_by_val(std::move(big), std::to_string(size(big))+'!', 'B'); std::cout << ">>> big=" << big << '\n'; ...
Noisy<StrVec> *, ce qui impliquerait que :
sv->emplace_back()par exemple) plutôt qu'un point,
for(auto &elem: *sv)par exemple),
&bigpar exemple).
int a=5; int &b=a; // ``b'' is a reference on ``a'' std::cout << "a=" << a << " b=" << b << '\n'; // a=5 b=5 ++b; // change the value referenced by ``b'' --> this changes ``a'' std::cout << "a=" << a << " b=" << b << '\n'; // a=6 b=6 ++a; // change ``a'' --> this is visible through ``b'' std::cout << "a=" << a << " b=" << b << '\n'; // a=7 b=7
&dans sa déclaration (juste avant son nom, comme le symbole
*dans la déclaration d'un pointeur) et est forcément initialisée depuis une donnée existante lors de sa déclaration (elle doit nécessairement référencer quelque chose !).
&dans la déclaration du paramètre en question (juste avant son nom, comme le symbole
*dans la déclaration d'un pointeur)✍
for(auto &elem: coord).
Noisy<StrVec> &.
void change_by_ref(Noisy<StrVec> &sv, std::string s, char c) { std::cout << "~~~~ enter " << __func__ << "() ~~~~\n"; sv.emplace_back(std::move(s)); for(auto &elem: sv) { elem+=c; } std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
... s4prc::change_by_ref(big, std::to_string(size(big))+'!', 'C'); std::cout << ">>> big=" << big << '\n'; ...
for(const auto &c: txt).
int total_length(const std::vector<std::string> &sv) { int result=0; for(const auto &elem: sv) { result+=int(size(elem)); } return result; }
auto big=s4prc::make_StrVec(10'000); int length=total_length(big);
void function_name(Type1 p1, // in-parameter (by value) const Type2 &p2, // in-parameter (by const-ref) Type3 &p3, // inout-parameter (by ref, maybe out?) Type4 &p4); // out-parameter (by ref, maybe in-out?)
<tuple>du langage C++ moderne expose le type std::tuple<...> qui représente un ensemble ordonné et fini d'éléments (un t-uplet en français) ; il s'agit en quelque sorte d'une structure anonyme dont les membres sont également anonymes.
std::tuple<int, char, double>est constitué, dans l'ordre, d'un entier, d'un caractère et d'un réel.
std::tuple<Noisy<std::string>, // even strings Noisy<std::string>, // odd strings int> // total length many_results(const Noisy<StrVec> &sv) { std::cout << "~~~~ enter " << __func__ << "() ~~~~\n"; Noisy<std::string> even, odd; int length=0, count=0; for(const auto &elem: sv) { (count++%2 ? odd : even)+=elem; length+=int(size(elem)); } std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; return {even, odd, length}; // !!! copies involved !!! (will be fixed later) }
... const auto [even_str, odd_str, total_length]=s4prc::many_results(big); std::cout << ">>> even_str=" << even_str << '\n'; std::cout << ">>> odd_str=" << odd_str << '\n'; std::cout << ">>> total_length=" << total_length << '\n'; ...
const auto results=s4prc::many_results(big); const auto &even_str=std::get<0>(results); const auto &odd_str=std::get<1>(results); const auto &total_length=std::get<2>(results);
s4prc::Noisy<std::string> even_str; s4prc::Noisy<std::string> odd_str; int total_length; std::tie(even_str, odd_str, total_length)=s4prc::many_results(big);
return {std::move(even), // std::move() prevents from std::move(odd), // copying existing locals std::move(length)}; // to tuple-members
void test_silent() { std::cout << "\n~~~~ " << __func__ << "() ~~~~\n"; using s4prc::operator<<; // compact display of StrVec and std::string auto big=s4prc::make_StrVec(10'000); std::cout << ">>> big=" << big << '\n'; big=s4prc::change_by_val(big, std::to_string(size(big))+'!', 'A'); std::cout << ">>> big=" << big << '\n'; big=s4prc::change_by_val(std::move(big), std::to_string(size(big))+'!', 'B'); std::cout << ">>> big=" << big << '\n'; s4prc::change_by_ref(big, std::to_string(size(big))+'!', 'C'); std::cout << ">>> big=" << big << '\n'; const auto [even_str, odd_str, total_length]=s4prc::many_results(big); std::cout << ">>> even_str=" << even_str << '\n'; std::cout << ">>> odd_str=" << odd_str << '\n'; std::cout << ">>> total_length=" << total_length << '\n'; }
#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()); }
<chrono>fournit un éventail très complet d'utilitaires autour des notions d'horloge, d'instant, de durée et des moyens de conversion entre les différentes unités impliquées (voir cette section).
void test_perf() { std::cout << "\n~~~~ " << __func__ << "() ~~~~\n"; using s4prc::operator<<; // compact display of StrVec and std::string const int initial_count=10'000; const int iter_count=1'000; if(1) { auto big=s4prc::make_StrVec(initial_count); const double t0=get_time(); for(int i=0; i<iter_count; ++i) { big=s4prc::change_by_val(big, std::to_string(size(big))+'!', 'A'); } const double dt=get_time()-t0; std::cout << "change_by_val() takes " << dt << " s\n"; std::cout << ">>> big=" << big << '\n'; } if(1) { // same kind of measure on s4prc::change_by_val(std::move(big), ... ,'B') } if(1) { // same kind of measure on s4prc::change_by_ref(big, ... ,'C') } if(1) { // same kind of measure on s4prc::many_results(big) } }
const std::string *stringset
int string_countcomme paramètres en lieu et place de
const std::vector<std::string> &sv; ceci la rendrait tout aussi bien applicable à une donnée de type
std::array<std::string>, ou encore à un sous ensemble d'une donnée de type
std::vector<std::string>(si nous l'invoquions avec data(big)+1000 et int(size(big))-5000 par exemple).
//----------------------------------------------------------------------------
#ifndef S4PRC_NOISY_HPP #define S4PRC_NOISY_HPP
#include <iostream> #include <string> #include <vector>
namespace s4prc {
inline std::ostream & operator<<(std::ostream &output, const std::string &s) // display string within quotes { using std::operator<<; output << '"'; if(const auto sz=size(s); sz>20) // prevent from using too much space { output << s.substr(0, 10) << "..." << s.substr(sz-10); } else { output << s; } return output << '"'; }
template<typename E> inline std::ostream & operator<<(std::ostream &output, const std::vector<E> &v) // display vector within braces { output << '{'; if(const auto sz=size(v); sz>4) // prevent from using too much space { output << v[0] << ',' << v[1] << ",...," << v[sz-2] << ',' << v[sz-1]; } else { int count=0; for(const auto &elem: v) { if(count++) { output << ','; } output << elem; } } return output << '}'; }
template<typename T> struct Noisy : T { Noisy() : T{} { std::cout << "construct " << *this << " from nothing\n"; }
Noisy(const T &t) : T{t} { std::cout << "copy-construct " << *this << "\n ... from " << t << '\n'; }
Noisy(T &&t) : T{std::move(t)} { std::cout << "move-construct " << *this << "\n ... from (moved) " << t << '\n'; }
Noisy(const Noisy &n) : T{static_cast<const T &>(n)} { std::cout << "copy-construct " << *this << "\n ... from " << n << '\n'; }
Noisy(Noisy &&n) noexcept : T{std::move(static_cast<T &&>(n))} { std::cout << "move-construct " << *this << "\n ... from (moved) " << n << '\n'; }
Noisy & operator=(const T &t) { T::operator=(t); std::cout << "copy-assign " << *this << "\n ... from " << t << '\n'; return *this; }
Noisy & operator=(T &&t) { T::operator=(std::move(t)); std::cout << "move-assign " << *this << "\n ... from (moved) " << t << '\n'; return *this; }
Noisy & operator=(const Noisy &n) { T::operator=(static_cast<const T &>(n)); std::cout << "copy-assign " << *this << "\n ... from " << n << '\n'; return *this; }
Noisy & operator=(Noisy &&n) noexcept { T::operator=(std::move(static_cast<T &&>(n))); std::cout << "move-assign " << *this << "\n ... from (moved) " << n << '\n'; return *this; }
~Noisy() { std::cout << "destroy " << *this << '\n'; }
friend std::ostream & operator<<(std::ostream &output, const Noisy &n) { return output << "Noisy@" << &n << ":" << static_cast<const T &>(n); } };
} // namespace s4prc
#endif // S4PRC_NOISY_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifndef S4PRC_STR_VEC_HPP #define S4PRC_STR_VEC_HPP
#include "noisy.hpp" #include <tuple>
namespace s4prc {
using StrVec = std::vector<std::string>;
StrVec make_StrVec(int count);
//---- noisy functions ----
Noisy<StrVec> change_by_val(Noisy<StrVec> sv, std::string s, char c);
void change_by_ref(Noisy<StrVec> &sv, std::string s, char c);
std::tuple<Noisy<std::string>, // even strings Noisy<std::string>, // odd strings int> // total length many_results(const Noisy<StrVec> &sv);
//---- silent functions ----
StrVec change_by_val(StrVec sv, std::string s, char c);
void change_by_ref(StrVec &sv, std::string s, char c);
std::tuple<std::string, // even strings std::string, // odd strings int> // total length many_results(const StrVec &sv);
} // namespace s4prc
#endif // S4PRC_STR_VEC_HPP
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include "str_vec.hpp"
namespace s4prc {
StrVec make_StrVec(int count) { StrVec result; for(int i=0; i<count; ++i) { result.emplace_back("str"+std::to_string(i)); } return result; }
//---- noisy functions ----
Noisy<StrVec> change_by_val(Noisy<StrVec> sv, std::string s, char c) { std::cout << "~~~~ enter " << __func__ << "() ~~~~\n"; sv.emplace_back(std::move(s)); for(auto &elem: sv) { elem+=c; } std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; return sv; }
void change_by_ref(Noisy<StrVec> &sv, std::string s, char c) { std::cout << "~~~~ enter " << __func__ << "() ~~~~\n"; sv.emplace_back(std::move(s)); for(auto &elem: sv) { elem+=c; } std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; }
std::tuple<Noisy<std::string>, // even strings Noisy<std::string>, // odd strings int> // total length many_results(const Noisy<StrVec> &sv) { std::cout << "~~~~ enter " << __func__ << "() ~~~~\n"; Noisy<std::string> even, odd; int length=0, count=0; for(const auto &elem: sv) { (count++%2 ? odd : even)+=elem; length+=int(size(elem)); } std::cout << "~~~~ leave " << __func__ << "() ~~~~\n"; #if 0 return {even, odd, length}; // copies involved! #else return {std::move(even), // std::move() prevents from std::move(odd), // copying existing locals std::move(length)}; // to tuple-members #endif }
//---- silent functions ----
StrVec change_by_val(StrVec sv, std::string s, char c) { sv.emplace_back(std::move(s)); for(auto &elem: sv) { elem+=c; } return sv; }
void change_by_ref(StrVec &sv, std::string s, char c) { sv.emplace_back(std::move(s)); for(auto &elem: sv) { elem+=c; } }
std::tuple<std::string, // even strings std::string, // odd strings int> // total length many_results(const StrVec &sv) { std::string even, odd; int length=0, count=0; for(const auto &elem: sv) { (count++%2 ? odd : even)+=elem; length+=int(size(elem)); } return {std::move(even), // std::move() prevents from std::move(odd), // copying existing locals std::move(length)}; // to tuple-members }
} // namespace s4prc
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#include "str_vec.hpp" #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()); }
void test_noisy() { std::cout << "\n~~~~ enter " << __func__ << "() ~~~~\n"; s4prc::Noisy<s4prc::StrVec> big=s4prc::make_StrVec(10'000); std::cout << ">>> big=" << big << '\n'; big=s4prc::change_by_val(big, std::to_string(size(big))+'!', 'A'); std::cout << ">>> big=" << big << '\n'; big=s4prc::change_by_val(std::move(big), std::to_string(size(big))+'!', 'B'); std::cout << ">>> big=" << big << '\n'; s4prc::change_by_ref(big, std::to_string(size(big))+'!', 'C'); std::cout << ">>> big=" << big << '\n'; const auto [even_str, odd_str, total_length]=s4prc::many_results(big); std::cout << ">>> even_str=" << even_str << '\n'; std::cout << ">>> odd_str=" << odd_str << '\n'; std::cout << ">>> total_length=" << total_length << '\n'; }
void test_silent() { std::cout << "\n~~~~ " << __func__ << "() ~~~~\n"; using s4prc::operator<<; // compact display of StrVec and std::string auto big=s4prc::make_StrVec(10'000); std::cout << ">>> big=" << big << '\n'; big=s4prc::change_by_val(big, std::to_string(size(big))+'!', 'A'); std::cout << ">>> big=" << big << '\n'; big=s4prc::change_by_val(std::move(big), std::to_string(size(big))+'!', 'B'); std::cout << ">>> big=" << big << '\n'; s4prc::change_by_ref(big, std::to_string(size(big))+'!', 'C'); std::cout << ">>> big=" << big << '\n'; const auto [even_str, odd_str, total_length]=s4prc::many_results(big); std::cout << ">>> even_str=" << even_str << '\n'; std::cout << ">>> odd_str=" << odd_str << '\n'; std::cout << ">>> total_length=" << total_length << '\n'; }
void test_perf() { std::cout << "\n~~~~ " << __func__ << "() ~~~~\n"; #if !defined NDEBUG std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" " Built for debug purpose at first " "(measurements will not be relevant).\n" " For an actual experiment, rebuild with: " " make rebuild opt=1\n" "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"; #endif using s4prc::operator<<; // compact display of StrVec and std::string const int initial_count=10'000; const int iter_count=1'000; if(1) { auto big=s4prc::make_StrVec(initial_count); const double t0=get_time(); for(int i=0; i<iter_count; ++i) { big=s4prc::change_by_val(big, std::to_string(size(big))+'!', 'A'); } const double dt=get_time()-t0; std::cout << "change_by_val() takes " << dt << " s\n"; std::cout << ">>> big=" << big << '\n'; } if(1) { auto big=s4prc::make_StrVec(initial_count); const double t0=get_time(); for(int i=0; i<iter_count; ++i) { big=s4prc::change_by_val(std::move(big), std::to_string(size(big))+'!', 'B'); } const double dt=get_time()-t0; std::cout << "change_by_val(std::move()) takes " << dt << " s\n"; std::cout << ">>> big=" << big << '\n'; } if(1) { auto big=s4prc::make_StrVec(initial_count); const double t0=get_time(); for(int i=0; i<iter_count; ++i) { s4prc::change_by_ref(big, std::to_string(size(big))+'!', 'C'); } const double dt=get_time()-t0; std::cout << "change_by_ref() takes " << dt << " s\n"; std::cout << ">>> big=" << big << '\n'; } if(1) { auto big=s4prc::make_StrVec(initial_count); std::string even_str; std::string odd_str; int total_length; const double t0=get_time(); for(int i=0; i<iter_count; ++i) { std::tie(even_str, odd_str, total_length)=s4prc::many_results(big); } const double dt=get_time()-t0; std::cout << "many_results() takes " << dt << " s\n"; std::cout << ">>> big=" << big << '\n'; std::cout << ">>> even_str=" << even_str << '\n'; std::cout << ">>> odd_str=" << odd_str << '\n'; std::cout << ">>> total_length=" << total_length << '\n'; } }
int main() { test_noisy(); test_silent(); test_perf(); return 0; }
//----------------------------------------------------------------------------
return {std::move(result_0), std::move(result_1), ..., std::move(result_N)};
auto [result_0, result_1, ..., result_N]=function_providing_many_results(...);