C ++ рдореВрд▓реНрдп рд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдХрд╛ рддреНрд╡рд░рд┐рдд рд╕рдВрджрд░реНрдн: рднрд╛рдЧ 2




1 рднрд╛рдЧ 1 рдкрд░ рдЬрд╛рдПрдВ


рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рдкрд╛рд░рд┐рдд рдХрд░рдирд╛


рдЬрдм рдХрд┐рд╕реА рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдПрдХ рдкрд╛рд░рд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреА рд╢реНрд░реЗрдгреА рдХреЛ рдлрд╝рдВрдХреНрд╢рди рдкреИрд░рд╛рдореАрдЯрд░ рдХреА рд╢реНрд░реЗрдгреА рдореЗрдВ рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ: void f(TO_TYPE p); FROM_TYPE x; f(x); void f(TO_TYPE p); FROM_TYPE x; f(x); рдпрд╣ рдирд┐рд╣рд┐рдд рд░реВрдкрд╛рдВрддрд░рдг рдЙрд╕реА рддрд░рд╣ рд╣реЛрддрд╛ рд╣реИ рдЬреИрд╕реЗ рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рдХреЗ рджреМрд░рд╛рди (рдКрдкрд░ "рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ" рдЕрдиреБрднрд╛рдЧ рджреЗрдЦреЗрдВ) рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдлрд╝рдВрдХреНрд╢рди рдкрд░рд┐рднрд╛рд╖рд╛ рдореЗрдВ "рдСрдЯреЛ" рдкреНрд░рдХрд╛рд░ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреЗред



рдЬрдм рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдПрдХ рд╣реА рд╕рдВрдЦреНрдпрд╛ рдФрд░ рдХрдИ рдкреНрд░рдХрд╛рд░ рдХреЗ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рдХрдИ рдЕрдзрд┐рднрд╛рд░ рд╣реЛрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╡рд┐рднрд┐рдиреНрди рд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдХреЗ рдкреИрд░рд╛рдореАрдЯрд░, рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ рддрдВрддреНрд░ рд╢реНрд░реЗрдгреА рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд▓рд╛рдЧреВ рдлрд╝рдВрдХреНрд╢рди рдЕрдзрд┐рднрд╛рд░ рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИред рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдиреАрдЪреЗ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдЕрдзрд┐рднрд╛рд░ рдХреЛ рдПрдХ рдЖрджреЗрд╢ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рд╢реНрд░реЗрдгреА рдХреА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдЙрддреНрддреАрд░реНрдг рдХрд░рддреЗ рд╕рдордп рдкреНрд░рддреНрдпреЗрдХ рдЕрдзрд┐рднрд╛рд░ рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг 1 рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдпрд╣ рдЕрдзрд┐рднрд╛рд░ рд╣рдореЗрд╢рд╛ рдЙрдкрд▓рдмреНрдз рд╣реЛрдиреЗ рдкрд░ рдкрд╣рд▓реЗ рдЪреБрдирд╛ рдЬрд╛рдПрдЧрд╛):



рдлреБрдЯрдиреЛрдЯ:


1 - рдПрдХ рд░реЗрдлрд░реЗрдВрд╕ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝рд░ рдХреЛ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдПрдХ рдЕрд╕реНрдерд╛рдпреА рдлрдВрдХреНрд╢рди рд╕реНрдХреЛрдк рдХреЗ рдЕрдВрдд рддрдХ рдмрдирд╛ рд░рд╣рддрд╛ рд╣реИред


рдзреНрдпрд╛рди рджреЗрдВ:


  • рдпрджрд┐ рдХреЛрдИ рдлрд╝рдВрдХреНрд╢рди рдорд╛рди рд╕реЗ рдкреИрд░рд╛рдореАрдЯрд░ рд▓реЗрддрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рд╣рдореЗрд╢рд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рд╕реНрд░реЛрдд рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдмрджрд▓ рдирд╣реАрдВ рд╕рдХрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдорд╛рди рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдореВрд╡ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рд╕реНрд░реЛрдд рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
  • рдЖрдкрдХреЗ рдкрд╛рд╕ T f() рдФрд░ const T f() рдлрдВрдХреНрд╢рди рдУрд╡рд░рд▓реЛрдб рджреЛрдиреЛрдВ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреЗ
  • рдкреИрд░рд╛рдореАрдЯрд░ рдПрдХ рд╕рдВрджрд░реНрдн рд╣реИ рдпрд╛ рдирд╣реАрдВ, рдЗрд╕рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдУрд╡рд░рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рджреЛрдиреЛрдВ рдлрд╝рдВрдХреНрд╢рди рддрд░реНрдХ рд▓реЗ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдЕрд╕реНрдкрд╖реНрдЯрддрд╛ рдХреЛ рдореИрдиреБрдЕрд▓ рд╣рд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ (рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдлрд╝рдВрдХреНрд╢рди рдкреЙрдЗрдВрдЯрд░ рдкреНрд░рдХрд╛рд░ рд╕реЗ рдХрд╛рд╕реНрдЯрд┐рдВрдЧ рдХрд░рдХреЗ)ред
  • рдЕрдЧреНрд░реЗрд╖рдг рд╕рдВрджрд░реНрдн рд╕рдмрд╕реЗ "рд▓рд╛рд▓рдЪреА" рд╣реИ - рдпрд╣ рдЬреАрддрддрд╛ рд╣реИ рдЬреИрд╕реЗ рд╣реА рд╕рдЯреАрдХ рдореИрдЪ рдХреЗ рд╕рд╛рде рдХреЛрдИ рдЕрдзрд┐рднрд╛рд░ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП рдПрдХ рдЕрдЧреНрд░реЗрд╖рдг рд╕рдВрджрд░реНрдн рдХреЛ рдЕрдзрд┐рднрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрдорддреМрд░ рдкрд░ рдЕрдиреБрд╢рдВрд╕рд╛ рдирд╣реАрдВ рдХреА рдЬрд╛рддреА рд╣реИ (рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, FR рд╕реЗ рдмрдЪреЗрдВ рдпрд╛ рдУрд╡рд░рд▓реЛрдбрд┐рдВрдЧ рд╕реЗ рдмрдЪрдиреЗ рдпрд╛ рдЯреИрдЧ рдкреНрд░реЗрд╖рдг рдпрд╛ SFINA рд▓рд┐рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ)ред рдПрдХ рдЕрдЧреНрд░реЗрд╖рдг рд╕рдВрджрд░реНрдн рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдХреЙрдкреА рдФрд░ рдирд┐рд░реНрдорд╛рдг рдмрд┐рд▓реНрдбрд░реЛрдВ рдХреЗ рд╕рд╛рде рд╕рдВрдШрд░реНрд╖ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
  • рдЕрдЧреНрд░реЗрд╖рдг рд╕рдВрджрд░реНрдн рд╕рдВрдХрд▓рдХ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рд╕рдордЭрдиреЗ рдФрд░ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдФрд░ рдЕрдзрд┐рдХ рдХрдард┐рди рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЦрд╛рд╕рдХрд░ рдпрджрд┐ рд╡реЗ рдХрдИ рдмрд╛рд░ рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред
  • рдЕрдЧреНрд░реЗрд╖рдг рд╕рдВрджрд░реНрдн рдирд┐рдореНрди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ:
    • рдЖрдк рдЖрдЧреЗ рдХреЗ рд╕рдВрджрд░реНрдн рдХреЗ рд╕рд╛рде vector<int> рд▓рд┐рдП {1, 2, 3} рдХреЛ рдЕрдЧреНрд░реЗрд╖рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред
    • рдЖрдк рдПрдХ рдлреЙрд░рд╡рд░реНрдбрд┐рдВрдЧ рд░реЗрдлрд░реЗрдВрд╕ рдХреЗ рд╕рд╛рде 0 рдпрд╛ NULL рдХреЛ рдкреЙрдЗрдВрдЯрд░ рдкрд░ рдлреЙрд░рд╡рд░реНрдб рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ (рдЗрд╕рдХреЗ рдмрдЬрд╛рдп nullptr рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ)ред
    • рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдХреЛрдИ рдкрд░рд┐рднрд╛рд╖рд╛ рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдк рдкреВрд░реНрдгрд╛рдВрдХ рд╕реНрдерд┐рд░ рд╕реНрдерд┐рд░рд╛рдВрдХ рдФрд░ рдХреЙрдиреНрд╕реНрдЯреЗрдХреНрд╕ рд╕рджрд╕реНрдп рдЪрд░ рдХреЛ рдЕрдЧреНрд░реЗрд╖рд┐рдд рд╕рдВрджрд░реНрдн рдХреЗ рд╕рд╛рде рдЕрдЧреНрд░реЗрд╖рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред
    • рдЖрдк рдЕрдЧреНрд░реЗрд╖рд┐рдд рд╕рдВрджрд░реНрдн рдХреЗ рд╕рд╛рде рдЕрддрд┐рднрд╛рд░рд┐рдд рдлрд╝рдВрдХреНрд╢рди рдпрд╛ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдЕрдЧреНрд░реЗрд╖рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдЕрд╕реНрдкрд╖реНрдЯрддрд╛ рдмрдирд╛рддрд╛ рд╣реИ (рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкреНрд░рдХрд╛рд░ рджреНрд╡рд╛рд░рд╛ рд╡рд┐рдШрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ)ред

рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд░реНрдорд╛рддрд╛ рдФрд░ рдСрдкрд░реЗрдЯрд░ рдХреЗ рдореБрджреНрд░рдг рдХреЗ рд╕рд╛рде рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдФрд░ рдкрд░реАрдХреНрд╖рдг:


рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд░реНрдорд╛рддрд╛ рдФрд░ рдСрдкрд░реЗрдЯрд░ рдХреЗ рдореБрджреНрд░рдг рдХреЗ рд╕рд╛рде рдЙрджрд╛рд╣рд░рдг рдФрд░ рдкрд░реАрдХреНрд╖рдг
 #include <iostream> #include <iomanip> #include <map> #include <vector> #include <string> using namespace std; template<class C, class T> auto contains(const C& v, const T& x) -> decltype(end(v), true) { return end(v) != std::find(begin(v), end(v), x); } template <class... Types> constexpr inline __attribute__((__always_inline__)) int UNUSED(Types&&...) { return 0; }; map<string, map<string, string>> res; vector<string> froms; vector<string> tos; string from; string to; int ready = 0; void report(string st) { if (!from.empty() && !to.empty()) { res[from][to] += st; } if (ready) cout << st << " "; } struct T { T() { report("Dc"); } T(int va) : a(va) { report("Pc"); } T(const T& other) : a(other.a) { report("Cc"); } T(T&& other) : a(std::exchange(other.a, 0)) { report("Mc"); } T& operator=(int va) { report("Va"); a = va; return *this; } T& operator=(const T& rhs) { report("Ca"); // check for self-assignment if(&rhs == this) return *this; a = rhs.a; return *this; } T& operator=(T&& rhs) { report("Ma"); // check for self-assignment if(&rhs == this) return *this; a = std::exchange(rhs.a, 0); return *this; } ~T() { report("D"); } int a = 1; }; void func_start() { cout << "|"; } T Fprv() { return T(4); } const T Fcprv() { return T(5); } T gs; void t(T s) { func_start(); cout << sa; } void ct(const T s) { func_start(); cout << sa; } void tr(T& s) { func_start(); cout << sa; } void ctr(const T& s) { func_start(); cout << sa; } void trr(T&& s) { func_start(); cout << sa; } void ctrr(const T&& s) { func_start(); cout << sa; } template<typename Z> void pf(Z&& s) { func_start(); gs = forward<Z>(s); cout << gs.a; } void print_col(const string &st, int width) { cout << endl << left << setw(width) << st; } void test_pass(string lto, string lfrom) { from = lfrom; to = lto; res[from][to] = ""; if (!from.empty() && !to.empty()) { if (!contains(froms, from)) froms.push_back(from); if (!contains(tos, to)) tos.push_back(to); } print_col(lto + "(" + lfrom + "): ", 20); } #define EVAL(x) #x #define TEST_PASS(t, v) { \ test_pass(EVAL(t), #v); \ t(v); \ cout << "-"; \ } void test_conversion() { ready = 1; T LV; const T CLV; T& LR = LV; const T& CLR = LV; //T&& XV = T(); -- actually LR //const T&& CXV = T(); -- actually LR auto &&fr = T(); #undef DT #define DT t TEST_PASS(DT, 2); TEST_PASS(DT, Fprv()); TEST_PASS(DT, Fcprv()); TEST_PASS(DT, LV); TEST_PASS(DT, CLV); TEST_PASS(DT, LR); TEST_PASS(DT, CLR); TEST_PASS(DT, move(LV)); TEST_PASS(DT, move(CLV)); TEST_PASS(DT, fr); #undef DT #define DT ct TEST_PASS(DT, 2); TEST_PASS(DT, Fprv()); TEST_PASS(DT, Fcprv()); TEST_PASS(DT, LV); TEST_PASS(DT, CLV); TEST_PASS(DT, LR); TEST_PASS(DT, CLR); TEST_PASS(DT, move(LV)); TEST_PASS(DT, move(CLV)); TEST_PASS(DT, fr); #undef DT #define DT tr //TEST_PASS(DT, 2); //TEST_PASS(DT, Fprv()); //TEST_PASS(DT, Fcprv()); TEST_PASS(DT, LV); //TEST_PASS(DT, CLV); TEST_PASS(DT, LR); //TEST_PASS(DT, CLR); //TEST_PASS(DT, move(LV)); //TEST_PASS(DT, move(CLV)); TEST_PASS(DT, fr); #undef DT #define DT ctr TEST_PASS(DT, 2); TEST_PASS(DT, Fprv()); TEST_PASS(DT, Fcprv()); TEST_PASS(DT, LV); TEST_PASS(DT, CLV); TEST_PASS(DT, LR); TEST_PASS(DT, CLR); TEST_PASS(DT, move(LV)); TEST_PASS(DT, move(CLV)); TEST_PASS(DT, fr); #undef DT #define DT trr TEST_PASS(DT, 2); TEST_PASS(DT, Fprv()); //TEST_PASS(DT, Fcprv()); //TEST_PASS(DT, LV); //TEST_PASS(DT, CLV); //TEST_PASS(DT, LR); //TEST_PASS(DT, CLR); TEST_PASS(DT, move(LV)); //TEST_PASS(DT, move(CLV)); //TEST_PASS(DT, fr); #undef DT #define DT ctrr TEST_PASS(DT, 2); TEST_PASS(DT, Fprv()); TEST_PASS(DT, Fcprv()); //TEST_PASS(DT, LV); //TEST_PASS(DT, CLV); //TEST_PASS(DT, LR); //TEST_PASS(DT, CLR); TEST_PASS(DT, move(LV)); TEST_PASS(DT, move(CLV)); //TEST_PASS(DT, fr); #undef DT #define DT pf TEST_PASS(DT, 2); TEST_PASS(DT, Fprv()); TEST_PASS(DT, Fcprv()); TEST_PASS(DT, LV); TEST_PASS(DT, CLV); TEST_PASS(DT, LR); TEST_PASS(DT, CLR); TEST_PASS(DT, move(LV)); TEST_PASS(DT, move(CLV)); TEST_PASS(DT, fr); cout << endl; const int twidth = 10; cout << left << setw(twidth) << "From:"; for (const auto& lto : tos) { cout << left << setw(twidth) << lto; } cout << endl; for (const auto& lfrom : froms) { cout << left << setw(twidth) << lfrom; for (const auto& lto : tos) { if (!res.count(lfrom) || !res[lfrom].count(lto)) { cout << left << setw(twidth) << "-"; } else if (res[lfrom][lto].empty()) { cout << left << setw(twidth) << "+"; } else { cout << left << setw(twidth) << res[lfrom][lto]; } } cout << endl; } cout << endl; } int main() { test_conversion(); cout << endl; return 0; } /* Output: Dc Dc Dc t(2): Pc |2D - t(Fprv()): Pc |4D - t(Fcprv()): Pc |5D - t(LV): Cc |1D - t(CLV): Cc |1D - t(LR): Cc |1D - t(CLR): Cc |1D - t(move(LV)): Mc |1D - t(move(CLV)): Cc |1D - t(fr): Cc |1D - ct(2): Pc |2D - ct(Fprv()): Pc |4D - ct(Fcprv()): Pc |5D - ct(LV): Cc |0D - ct(CLV): Cc |1D - ct(LR): Cc |0D - ct(CLR): Cc |0D - ct(move(LV)): Mc |0D - ct(move(CLV)): Cc |1D - ct(fr): Cc |1D - tr(LV): |0- tr(LR): |0- tr(fr): |1- ctr(2): Pc |2D - ctr(Fprv()): Pc |4D - ctr(Fcprv()): Pc |5D - ctr(LV): |0- ctr(CLV): |1- ctr(LR): |0- ctr(CLR): |0- ctr(move(LV)): |0- ctr(move(CLV)): |1- ctr(fr): |1- trr(2): Pc |2D - trr(Fprv()): Pc |4D - trr(move(LV)): |0- ctrr(2): Pc |2D - ctrr(Fprv()): Pc |4D - ctrr(Fcprv()): Pc |5D - ctrr(move(LV)): |0- ctrr(move(CLV)): |1- pf(2): |Va 2- pf(Fprv()): Pc |Ma 4D - pf(Fcprv()): Pc |Ca 5D - pf(LV): |Ca 0- pf(CLV): |Ca 1- pf(LR): |Ca 0- pf(CLR): |Ca 0- pf(move(LV)): |Ma 0- pf(move(CLV)): |Ca 1- pf(fr): |Ca 1- From: t ct tr ctr trr ctrr pf 2 PcD PcD - PcD PcD PcD Va Fprv() PcD PcD - PcD PcD PcD PcMaD Fcprv() PcD PcD - PcD - PcD PcCaD LV CcD CcD + + - - Ca CLV CcD CcD - + - - Ca LR CcD CcD + + - - Ca CLR CcD CcD - + - - Ca move(LV) McD McD - + + + Ma move(CLV) CcD CcD - + - + Ca fr CcD CcD + + - - Ca DDD */ 

рд▓рд┐рдВрдХ:


рдЕрдзрд┐рднрд╛рд░ рдХрд╛ рд╕рдВрдХрд▓реНрдк
рдХреЙрдиреНрд╕реНрдЯ рд░реЗрдлрд░реЗрдВрд╕ рдмрдирд╛рдо рдореВрд╡ рд╢рдмреНрджрд╛рд░реНрде
рдорд╛рди рдФрд░ рдПрд╕рдЯреАрдбреА рджреНрд╡рд╛рд░рд╛ рдкрд╛рд╕ рдХреЗ рд▓рд╛рдн :: рд╕рдВрджрд░реНрдн рджреНрд╡рд╛рд░рд╛ рдкрд╛рд╕ рд╕реЗ рдЖрдЧреЗ рдмрдврд╝реЗрдВ


рдПрдХ рд╕рдорд╛рд░реЛрд╣ рд╕реЗ рд▓реМрдЯрддреЗ рд╣реБрдП


рдХрд┐рд╕реА рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдХреЛрдИ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╡рд╛рдкрд╕ рдХрд░рддреЗ рд╕рдордп, рд▓реМрдЯреЗ рд╣реБрдП рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреА рд╢реНрд░реЗрдгреА FROM_TYPE рдлрд╝рдВрдХреНрд╢рди рд░рд┐рдЯрд░реНрди рдкреНрд░рдХрд╛рд░ RETURN_TYPE рдХреА рд╢реНрд░реЗрдгреА рдХреЛ рдмреЗрдореЗрд▓ рдХрд░ рд╕рдХрддреА рд╣реИ, рдЬреЛ рдЕрд╕рд╛рдЗрди рдХрд┐рдП рдЧрдП рдЪрд░ TO_TYPE рдХреА рд╢реНрд░реЗрдгреА рдХреЛ рдмреЗрдореЗрд▓ рдХрд░ рд╕рдХрддреА рд╣реИ: RETURN_TYPE f() { FROM_TYPE x; return x; } TO_TYPE y = f(); RETURN_TYPE f() { FROM_TYPE x; return x; } TO_TYPE y = f();


рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдирд┐рд╣рд┐рдд рд░реВрдкрд╛рдВрддрд░рдг рджреЛ рдмрд╛рд░ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ:


  • FROM_TYPE рд╕реЗ RETURN TYPE рдореЗрдВ рдХрдирд╡рд░реНрдЯ рдХрд░рддреЗ рд╕рдордпред рдпрд╣ рд░реВрдкрд╛рдВрддрд░рдг рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рдХреЗ рджреМрд░рд╛рди рд╡реИрд╕рд╛ рд╣реА рд╣реИ, рдЬреИрд╕реЗ рдкреАрдЖрд░рд╡реА рдпрд╛ рд╕реАрдкреАрдЖрд░рд╡реА рдХреЛ T &&, const T && рдпрд╛ const T & рдореЗрдВ рддрдмреНрджреАрд▓ рдХрд░рдиреЗ рдХреЗ рдЕрд▓рд╛рд╡рд╛ (рдРрд╕реЗ рд░реВрдкрд╛рдВрддрд░рдг рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреЗ, рдХреНрдпреЛрдВрдХрд┐ рдЕрд╕реНрдерд╛рдпреА рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдЬреАрд╡рдирдХрд╛рд▓ рдлрд╝рдВрдХреНрд╢рди рд╕реНрдХреЛрдк, рд▓рд┐рдВрдХ рд╕реЗ рдЕрдзрд┐рдХ рд▓рдВрдмрд╛ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛)
  • RETURN_TYPE рд╕реЗ TO_TYPE рдореЗрдВ рдХрдирд╡рд░реНрдЯ рдХрд░рддреЗ рд╕рдордп - рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рд░реВрдкрд╛рдВрддрд░рдг (рджреЗрдЦреЗрдВ "рдЙрдкрд░реЛрдХреНрдд рдореВрд▓реНрдп рд╢реНрд░реЗрдгрд┐рдпрд╛рдВ рдЕрд╕рд╛рдЗрди рдХрд░реЗрдВ")ред


рдлреБрдЯрдиреЛрдЯ:


1 - рдПрдХ рд╕рдВрджрд░реНрдн рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝рд░ рдХреЛ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рдХреЗ рджреМрд░рд╛рди рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдПрдХ рдЕрд╕реНрдерд╛рдпреА рдЕрдкрдиреЗ рд╕рдВрджрд░реНрдн рдХреЗ рджрд╛рдпрд░реЗ (рд▓рд╛рд▓ рдлрд╝реЙрдиреНрдЯ) рдХреЗ рдЕрдВрдд рддрдХ рдмрдирд╛ рд░рд╣рддрд╛ рд╣реИред


рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдХреЙрдкреА / рдореВрд╡ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдФрд░ рдСрдкрд░реЗрдЯрд░реЛрдВ рдХреА рдЫрдкрд╛рдИ рдХреЗ рд╕рд╛рде рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдФрд░ рдкрд░реАрдХреНрд╖рдг:


рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд░реНрдорд╛рддрд╛ рдФрд░ рдСрдкрд░реЗрдЯрд░ рдХреЗ рдореБрджреНрд░рдг рдХреЗ рд╕рд╛рде рдЙрджрд╛рд╣рд░рдг рдФрд░ рдкрд░реАрдХреНрд╖рдг
 #include <iostream> #include <iomanip> #include <map> #include <vector> #include <string> using namespace std; template<class C, class T> auto contains(const C& v, const T& x) -> decltype(end(v), true) { return end(v) != std::find(begin(v), end(v), x); } template <class... Types> constexpr inline __attribute__((__always_inline__)) int UNUSED(Types&&...) { return 0; }; map<string, map<string, string>> res; vector<string> froms; vector<string> tos; string from; string to; int ready = 0; void report(string st) { if (!from.empty() && !to.empty()) { res[from][to] += st; } if (ready) cout << st << " "; } struct T { T() { report("Dc"); } T(int va) : a(va) { report("Pc"); } T(const T& other) : a(other.a) { report("Cc"); } T(T&& other) : a(std::exchange(other.a, 0)) { report("Mc"); } T& operator=(int va) { report("Va"); a = va; return *this; } T& operator=(const T& rhs) { report("Ca"); // check for self-assignment if(&rhs == this) return *this; a = rhs.a; return *this; } T& operator=(T&& rhs) { report("Ma"); // check for self-assignment if(&rhs == this) return *this; a = std::exchange(rhs.a, 0); return *this; } ~T() { report("D"); } int a = 1; }; T lv; const T clv; T& lr = lv; T&& rr = std::move(lv); const T& clr = clv; const T&& crr = std::move(clv); auto&& arr = std::move(lv); T Fprv() { return T(); } const T Fcprv() { return T(); } void func_start() { cout << "|"; } T prv_t() { func_start(); return T(2); } const T prv_ct() { func_start(); return T(2); } // Prohibited (returning reference to temporary object): // T& prv_tr() { func_start(); return T(2); } // const T& prv_ctr() { func_start(); return T(2); } // T&& prv_trr() { func_start(); return T(2); } // const T&& prv_ctrr() { func_start(); return T(2); } template<typename Z> Z&& prv_fr() { func_start(); return Z(2); } /* Same as prv_ (I tested) T cprv_t() { func_start(); return Fcprv(); } const T cprv_ct() { func_start(); return Fcprv(); } // Prohibited (returning reference to temporary object): // T& cprv_tr() { func_start(); return Fcprv(); } // const T& cprv_ctr() { func_start(); return Fcprv(); } // T&& cprv_trr() { func_start(); return Fcprv(); } // const T&& cprv_ctrr() { func_start(); return Fcprv(); } template<typename Z> Z&& cprv_fr() { func_start(); return Fcprv(); } */ /* Same as prv_ (I tested) T lit_t() { func_start(); return 3; } const T lit_ct() { func_start(); return 3; } //T& lit_tr() { func_start(); return 3; } //const T& lit_ctr() { func_start(); return 3; } //T&& lit_trr() { func_start(); return 3; } //const T&& lit_ctrr() { func_start(); return 3; } template<typename Z> Z&& lit_fr() { func_start(); return 3; } */ T lr_t() { func_start(); return lr; } const T lr_ct() { func_start(); return lr; } T& lr_tr() { func_start(); return lr; } const T& lr_ctr() { func_start(); return lr; } //T&& lr_trr() { func_start(); return lr; } //const T&& lr_ctrr() { func_start(); return lr; } template<typename Z> Z&& lr_fr() { func_start(); return lr; } T clr_t() { func_start(); return clr; } const T clr_ct() { func_start(); return clr; } //T& clr_tr() { func_start(); return clr; } const T& clr_ctr() { func_start(); return clr; } //T&& clr_trr() { func_start(); return clr; } //const T&& clr_ctrr() { func_start(); return clr; } template<typename Z> Z&& clr_fr() { func_start(); return clr; } /* This is the same as xv and cxv (I tested it) T rr_t() { func_start(); return move(rr); } const T rr_ct() { func_start(); return move(rr); } //T& rr_tr() { func_start(); return move(rr); } const T& rr_ctr() { func_start(); return move(rr); } T&& rr_trr() { func_start(); return move(rr); } const T&& rr_ctrr() { func_start(); return move(rr); } template<typename Z> Z&& rr_fr() { func_start(); return move(rr); } T crr_t() { func_start(); return move(crr); } const T crr_ct() { func_start(); return move(crr); } //T& crr_tr() { func_start(); return move(crr); } const T& crr_ctr() { func_start(); return move(crr); } //T&& crr_trr() { func_start(); return move(crr); } const T&& crr_ctrr() { func_start(); return move(crr); } template<typename Z> Z&& crr_fr() { func_start(); return move(crr); } */ /* Same as lr_ (I tested) T arr_t() { func_start(); return arr; } const T arr_ct() { func_start(); return arr; } T& arr_tr() { func_start(); return arr; } const T& arr_ctr() { func_start(); return arr; } //T&& arr_trr() { func_start(); return arr; } //const T&& arr_ctrr() { func_start(); return arr; } template<typename Z> Z&& arr_fr() { func_start(); return arr; } */ T lv_t() { func_start(); return lv; } const T lv_ct() { func_start(); return lv; } T& lv_tr() { func_start(); return lv; } const T& lv_ctr() { func_start(); return lv; } //T&& lv_trr() { func_start(); return lv; } //const T&& lv_ctrr() { func_start(); return lv; } template<typename Z> Z&& lv_fr() { func_start(); return lv; } T xv_t() { func_start(); return move(lv); } const T xv_ct() { func_start(); return move(lv); } //T& xv_tr() { func_start(); return move(lv); } const T& xv_ctr() { func_start(); return move(lv); } T&& xv_trr() { func_start(); return move(lv); } const T&& xv_ctrr() { func_start(); return move(lv); } template<typename Z> Z&& xv_fr() { func_start(); return move(lv); } T clv_t() { func_start(); return clv; } const T clv_ct() { func_start(); return clv; } //T& clv_tr() { func_start(); return clv; } const T& clv_ctr() { func_start(); return clv; } //T&& clv_trr() { func_start(); return clv; } //const T&& clv_ctrr() { func_start(); return clv; } template<typename Z> Z&& clv_fr() { func_start(); return clv; } T cxv_t() { func_start(); return move(clv); } const T cxv_ct() { func_start(); return move(clv); } //T& cxv_tr() { func_start(); return move(clv); } const T& cxv_ctr() { func_start(); return move(clv); } //T&& cxv_trr() { func_start(); return move(clv); } const T&& cxv_ctrr() { func_start(); return move(clv); } template<typename Z> Z&& cxv_fr() { func_start(); return move(clv); } void print_col(const string &st, int width) { cout << endl << left << setw(width) << st; } void test_call(string lto, string lfrom) { from = lfrom; to = lto; res[from][to] = ""; if (!from.empty() && !to.empty()) { if (!contains(froms, from)) froms.push_back(from); if (!contains(tos, to)) tos.push_back(to); } print_col(lto + " = " + lfrom + ": ", 20); } #define EVAL(x) #x #define TEST_CALL(t, v) { \ test_call(EVAL(t), #v); \ ts = v(); \ cout << sa; \ UNUSED(s); \ cout << "-"; \ } void test_return() { ready = 1; cout << endl; #define DT T TEST_CALL(DT, prv_t); TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); TEST_CALL(DT, lr_t); TEST_CALL(DT, lr_ct); TEST_CALL(DT, lr_tr); TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); TEST_CALL(DT, clr_t); TEST_CALL(DT, clr_ct); TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); TEST_CALL(DT, lv_t); TEST_CALL(DT, lv_ct); TEST_CALL(DT, lv_tr); TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); TEST_CALL(DT, xv_t); TEST_CALL(DT, xv_ct); TEST_CALL(DT, xv_ctr); TEST_CALL(DT, xv_trr); TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); TEST_CALL(DT, clv_t); TEST_CALL(DT, clv_ct); TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); TEST_CALL(DT, cxv_t); TEST_CALL(DT, cxv_ct); TEST_CALL(DT, cxv_ctr); TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT const T TEST_CALL(DT, prv_t); TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); TEST_CALL(DT, lr_t); TEST_CALL(DT, lr_ct); TEST_CALL(DT, lr_tr); TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); TEST_CALL(DT, clr_t); TEST_CALL(DT, clr_ct); TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); TEST_CALL(DT, lv_t); TEST_CALL(DT, lv_ct); TEST_CALL(DT, lv_tr); TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); TEST_CALL(DT, xv_t); TEST_CALL(DT, xv_ct); TEST_CALL(DT, xv_ctr); TEST_CALL(DT, xv_trr); TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); TEST_CALL(DT, clv_t); TEST_CALL(DT, clv_ct); TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); TEST_CALL(DT, cxv_t); TEST_CALL(DT, cxv_ct); TEST_CALL(DT, cxv_ctr); TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT T& //TEST_CALL(DT, prv_t); //TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); //TEST_CALL(DT, lr_t); //TEST_CALL(DT, lr_ct); TEST_CALL(DT, lr_tr); //TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); //TEST_CALL(DT, clr_t); //TEST_CALL(DT, clr_ct); //TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); //TEST_CALL(DT, lv_t); //TEST_CALL(DT, lv_ct); TEST_CALL(DT, lv_tr); //TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); //TEST_CALL(DT, xv_t); //TEST_CALL(DT, xv_ct); //TEST_CALL(DT, xv_ctr); //TEST_CALL(DT, xv_trr); //TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); //TEST_CALL(DT, clv_t); //TEST_CALL(DT, clv_ct); //TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); //TEST_CALL(DT, cxv_t); //TEST_CALL(DT, cxv_ct); //TEST_CALL(DT, cxv_ctr); //TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT T&& TEST_CALL(DT, prv_t); //TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); TEST_CALL(DT, lr_t); //TEST_CALL(DT, lr_ct); //TEST_CALL(DT, lr_tr); //TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); TEST_CALL(DT, clr_t); //TEST_CALL(DT, clr_ct); //TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); TEST_CALL(DT, lv_t); //TEST_CALL(DT, lv_ct); //TEST_CALL(DT, lv_tr); //TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); TEST_CALL(DT, xv_t); //TEST_CALL(DT, xv_ct); //TEST_CALL(DT, xv_ctr); TEST_CALL(DT, xv_trr); //TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); TEST_CALL(DT, clv_t); //TEST_CALL(DT, clv_ct); //TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); TEST_CALL(DT, cxv_t); //TEST_CALL(DT, cxv_ct); //TEST_CALL(DT, cxv_ctr); //TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT const T&& TEST_CALL(DT, prv_t); TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); TEST_CALL(DT, lr_t); TEST_CALL(DT, lr_ct); //TEST_CALL(DT, lr_tr); //TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); TEST_CALL(DT, clr_t); TEST_CALL(DT, clr_ct); //TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); TEST_CALL(DT, lv_t); TEST_CALL(DT, lv_ct); //TEST_CALL(DT, lv_tr); //TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); TEST_CALL(DT, xv_t); TEST_CALL(DT, xv_ct); //TEST_CALL(DT, xv_ctr); TEST_CALL(DT, xv_trr); TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); TEST_CALL(DT, clv_t); TEST_CALL(DT, clv_ct); //TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); TEST_CALL(DT, cxv_t); TEST_CALL(DT, cxv_ct); //TEST_CALL(DT, cxv_ctr); TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT const auto&& TEST_CALL(DT, prv_t); TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); TEST_CALL(DT, lr_t); TEST_CALL(DT, lr_ct); //TEST_CALL(DT, lr_tr); //TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); TEST_CALL(DT, clr_t); TEST_CALL(DT, clr_ct); //TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); TEST_CALL(DT, lv_t); TEST_CALL(DT, lv_ct); //TEST_CALL(DT, lv_tr); //TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); TEST_CALL(DT, xv_t); TEST_CALL(DT, xv_ct); //TEST_CALL(DT, xv_ctr); TEST_CALL(DT, xv_trr); TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); TEST_CALL(DT, clv_t); TEST_CALL(DT, clv_ct); //TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); TEST_CALL(DT, cxv_t); TEST_CALL(DT, cxv_ct); //TEST_CALL(DT, cxv_ctr); TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT auto& //TEST_CALL(DT, prv_t); TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); //TEST_CALL(DT, lr_t); TEST_CALL(DT, lr_ct); TEST_CALL(DT, lr_tr); TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); //TEST_CALL(DT, clr_t); TEST_CALL(DT, clr_ct); TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); //TEST_CALL(DT, lv_t); TEST_CALL(DT, lv_ct); TEST_CALL(DT, lv_tr); TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); //TEST_CALL(DT, xv_t); TEST_CALL(DT, xv_ct); TEST_CALL(DT, xv_ctr); //TEST_CALL(DT, xv_trr); TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); //TEST_CALL(DT, clv_t); TEST_CALL(DT, clv_ct); TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); //TEST_CALL(DT, cxv_t); TEST_CALL(DT, cxv_ct); TEST_CALL(DT, cxv_ctr); TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT const T& TEST_CALL(DT, prv_t); TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); TEST_CALL(DT, lr_t); TEST_CALL(DT, lr_ct); TEST_CALL(DT, lr_tr); TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); TEST_CALL(DT, clr_t); TEST_CALL(DT, clr_ct); TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); TEST_CALL(DT, lv_t); TEST_CALL(DT, lv_ct); TEST_CALL(DT, lv_tr); TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); TEST_CALL(DT, xv_t); TEST_CALL(DT, xv_ct); TEST_CALL(DT, xv_ctr); TEST_CALL(DT, xv_trr); TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); TEST_CALL(DT, clv_t); TEST_CALL(DT, clv_ct); TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); TEST_CALL(DT, cxv_t); TEST_CALL(DT, cxv_ct); TEST_CALL(DT, cxv_ctr); TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT const auto& TEST_CALL(DT, prv_t); TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); TEST_CALL(DT, lr_t); TEST_CALL(DT, lr_ct); TEST_CALL(DT, lr_tr); TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); TEST_CALL(DT, clr_t); TEST_CALL(DT, clr_ct); TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); TEST_CALL(DT, lv_t); TEST_CALL(DT, lv_ct); TEST_CALL(DT, lv_tr); TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); TEST_CALL(DT, xv_t); TEST_CALL(DT, xv_ct); TEST_CALL(DT, xv_ctr); TEST_CALL(DT, xv_trr); TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); TEST_CALL(DT, clv_t); TEST_CALL(DT, clv_ct); TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); TEST_CALL(DT, cxv_t); TEST_CALL(DT, cxv_ct); TEST_CALL(DT, cxv_ctr); TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); #undef DT #define DT auto&& TEST_CALL(DT, prv_t); TEST_CALL(DT, prv_ct); //TEST_CALL(DT, prv_fr); TEST_CALL(DT, lr_t); TEST_CALL(DT, lr_ct); TEST_CALL(DT, lr_tr); TEST_CALL(DT, lr_ctr); //TEST_CALL(DT, lr_fr); TEST_CALL(DT, clr_t); TEST_CALL(DT, clr_ct); TEST_CALL(DT, clr_ctr); //TEST_CALL(DT, clr_fr); TEST_CALL(DT, lv_t); TEST_CALL(DT, lv_ct); TEST_CALL(DT, lv_tr); TEST_CALL(DT, lv_ctr); //TEST_CALL(DT, lv_fr); TEST_CALL(DT, xv_t); TEST_CALL(DT, xv_ct); TEST_CALL(DT, xv_ctr); TEST_CALL(DT, xv_trr); TEST_CALL(DT, xv_ctrr); //TEST_CALL(DT, xv_fr); TEST_CALL(DT, clv_t); TEST_CALL(DT, clv_ct); TEST_CALL(DT, clv_ctr); //TEST_CALL(DT, clv_fr); TEST_CALL(DT, cxv_t); TEST_CALL(DT, cxv_ct); TEST_CALL(DT, cxv_ctr); TEST_CALL(DT, cxv_ctrr); //TEST_CALL(DT, cxv_fr); cout << endl; const int twidth = 9; cout << left << setw(twidth) << "From:"; for (const auto& lto : tos) { cout << left << setw(twidth) << lto; } cout << endl; for (const auto& lfrom : froms) { cout << left << setw(twidth) << lfrom; for (const auto& lto : tos) { if (!res.count(lfrom) || !res[lfrom].count(lto)) { cout << left << setw(twidth) << "-"; } else if (res[lfrom][lto].empty()) { cout << left << setw(twidth) << "+"; } else { cout << left << setw(twidth) << res[lfrom][lto]; } } cout << endl; } } int main() { test_return(); return 0; } /* Output: T = prv_t: |Pc 2-D T = prv_ct: |Pc 2-D T = lr_t: |Cc 1-D T = lr_ct: |Cc 1-D T = lr_tr: |Cc 1-D T = lr_ctr: |Cc 1-D T = clr_t: |Cc 1-D T = clr_ct: |Cc 1-D T = clr_ctr: |Cc 1-D T = lv_t: |Cc 1-D T = lv_ct: |Cc 1-D T = lv_tr: |Cc 1-D T = lv_ctr: |Cc 1-D T = xv_t: |Mc 1-D T = xv_ct: |Mc 0-D T = xv_ctr: |Cc 0-D T = xv_trr: |Mc 0-D T = xv_ctrr: |Cc 0-D T = clv_t: |Cc 1-D T = clv_ct: |Cc 1-D T = clv_ctr: |Cc 1-D T = cxv_t: |Cc 1-D T = cxv_ct: |Cc 1-D T = cxv_ctr: |Cc 1-D T = cxv_ctrr: |Cc 1-D const T = prv_t: |Pc 2-D const T = prv_ct: |Pc 2-D const T = lr_t: |Cc 0-D const T = lr_ct: |Cc 0-D const T = lr_tr: |Cc 0-D const T = lr_ctr: |Cc 0-D const T = clr_t: |Cc 1-D const T = clr_ct: |Cc 1-D const T = clr_ctr: |Cc 1-D const T = lv_t: |Cc 0-D const T = lv_ct: |Cc 0-D const T = lv_tr: |Cc 0-D const T = lv_ctr: |Cc 0-D const T = xv_t: |Mc 0-D const T = xv_ct: |Mc 0-D const T = xv_ctr: |Cc 0-D const T = xv_trr: |Mc 0-D const T = xv_ctrr: |Cc 0-D const T = clv_t: |Cc 1-D const T = clv_ct: |Cc 1-D const T = clv_ctr: |Cc 1-D const T = cxv_t: |Cc 1-D const T = cxv_ct: |Cc 1-D const T = cxv_ctr: |Cc 1-D const T = cxv_ctrr: |Cc 1-D T& = lr_tr: |0- T& = lv_tr: |0- T&& = prv_t: |Pc 2-D T&& = lr_t: |Cc 0-D T&& = clr_t: |Cc 1-D T&& = lv_t: |Cc 0-D T&& = xv_t: |Mc 0-D T&& = xv_trr: |0- T&& = clv_t: |Cc 1-D T&& = cxv_t: |Cc 1-D const T&& = prv_t: |Pc 2-D const T&& = prv_ct: |Pc 2-D const T&& = lr_t: |Cc 0-D const T&& = lr_ct: |Cc 0-D const T&& = clr_t: |Cc 1-D const T&& = clr_ct: |Cc 1-D const T&& = lv_t: |Cc 0-D const T&& = lv_ct: |Cc 0-D const T&& = xv_t: |Mc 0-D const T&& = xv_ct: |Mc 0-D const T&& = xv_trr: |0- const T&& = xv_ctrr: |0- const T&& = clv_t: |Cc 1-D const T&& = clv_ct: |Cc 1-D const T&& = cxv_t: |Cc 1-D const T&& = cxv_ct: |Cc 1-D const T&& = cxv_ctrr: |1- const auto&& = prv_t: |Pc 2-D const auto&& = prv_ct: |Pc 2-D const auto&& = lr_t: |Cc 0-D const auto&& = lr_ct: |Cc 0-D const auto&& = clr_t: |Cc 1-D const auto&& = clr_ct: |Cc 1-D const auto&& = lv_t: |Cc 0-D const auto&& = lv_ct: |Cc 0-D const auto&& = xv_t: |Mc 0-D const auto&& = xv_ct: |Mc 0-D const auto&& = xv_trr: |0- const auto&& = xv_ctrr: |0- const auto&& = clv_t: |Cc 1-D const auto&& = clv_ct: |Cc 1-D const auto&& = cxv_t: |Cc 1-D const auto&& = cxv_ct: |Cc 1-D const auto&& = cxv_ctrr: |1- auto& = prv_ct: |Pc 2-D auto& = lr_ct: |Cc 0-D auto& = lr_tr: |0- auto& = lr_ctr: |0- auto& = clr_ct: |Cc 1-D auto& = clr_ctr: |1- auto& = lv_ct: |Cc 0-D auto& = lv_tr: |0- auto& = lv_ctr: |0- auto& = xv_ct: |Mc 0-D auto& = xv_ctr: |0- auto& = xv_ctrr: |0- auto& = clv_ct: |Cc 1-D auto& = clv_ctr: |1- auto& = cxv_ct: |Cc 1-D auto& = cxv_ctr: |1- auto& = cxv_ctrr: |1- const T& = prv_t: |Pc 2-D const T& = prv_ct: |Pc 2-D const T& = lr_t: |Cc 0-D const T& = lr_ct: |Cc 0-D const T& = lr_tr: |0- const T& = lr_ctr: |0- const T& = clr_t: |Cc 1-D const T& = clr_ct: |Cc 1-D const T& = clr_ctr: |1- const T& = lv_t: |Cc 0-D const T& = lv_ct: |Cc 0-D const T& = lv_tr: |0- const T& = lv_ctr: |0- const T& = xv_t: |Mc 0-D const T& = xv_ct: |Mc 0-D const T& = xv_ctr: |0- const T& = xv_trr: |0- const T& = xv_ctrr: |0- const T& = clv_t: |Cc 1-D const T& = clv_ct: |Cc 1-D const T& = clv_ctr: |1- const T& = cxv_t: |Cc 1-D const T& = cxv_ct: |Cc 1-D const T& = cxv_ctr: |1- const T& = cxv_ctrr: |1- const auto& = prv_t: |Pc 2-D const auto& = prv_ct: |Pc 2-D const auto& = lr_t: |Cc 0-D const auto& = lr_ct: |Cc 0-D const auto& = lr_tr: |0- const auto& = lr_ctr: |0- const auto& = clr_t: |Cc 1-D const auto& = clr_ct: |Cc 1-D const auto& = clr_ctr: |1- const auto& = lv_t: |Cc 0-D const auto& = lv_ct: |Cc 0-D const auto& = lv_tr: |0- const auto& = lv_ctr: |0- const auto& = xv_t: |Mc 0-D const auto& = xv_ct: |Mc 0-D const auto& = xv_ctr: |0- const auto& = xv_trr: |0- const auto& = xv_ctrr: |0- const auto& = clv_t: |Cc 1-D const auto& = clv_ct: |Cc 1-D const auto& = clv_ctr: |1- const auto& = cxv_t: |Cc 1-D const auto& = cxv_ct: |Cc 1-D const auto& = cxv_ctr: |1- const auto& = cxv_ctrr: |1- auto&& = prv_t: |Pc 2-D auto&& = prv_ct: |Pc 2-D auto&& = lr_t: |Cc 0-D auto&& = lr_ct: |Cc 0-D auto&& = lr_tr: |0- auto&& = lr_ctr: |0- auto&& = clr_t: |Cc 1-D auto&& = clr_ct: |Cc 1-D auto&& = clr_ctr: |1- auto&& = lv_t: |Cc 0-D auto&& = lv_ct: |Cc 0-D auto&& = lv_tr: |0- auto&& = lv_ctr: |0- auto&& = xv_t: |Mc 0-D auto&& = xv_ct: |Mc 0-D auto&& = xv_ctr: |0- auto&& = xv_trr: |0- auto&& = xv_ctrr: |0- auto&& = clv_t: |Cc 1-D auto&& = clv_ct: |Cc 1-D auto&& = clv_ctr: |1- auto&& = cxv_t: |Cc 1-D auto&& = cxv_ct: |Cc 1-D auto&& = cxv_ctr: |1- auto&& = cxv_ctrr: |1- From: T const T T& T&& const T&&const auto&&auto& const T& const auto&auto&& prv_t PcD PcD - PcD PcD PcD - PcD PcD PcD prv_ct PcD PcD - - PcD PcD PcD PcD PcD PcD lr_t CcD CcD - CcD CcD CcD - CcD CcD CcD lr_ct CcD CcD - - CcD CcD CcD CcD CcD CcD lr_tr CcD CcD + - - - + + + + lr_ctr CcD CcD - - - - + + + + clr_t CcD CcD - CcD CcD CcD - CcD CcD CcD clr_ct CcD CcD - - CcD CcD CcD CcD CcD CcD clr_ctr CcD CcD - - - - + + + + lv_t CcD CcD - CcD CcD CcD - CcD CcD CcD lv_ct CcD CcD - - CcD CcD CcD CcD CcD CcD lv_tr CcD CcD + - - - + + + + lv_ctr CcD CcD - - - - + + + + xv_t McD McD - McD McD McD - McD McD McD xv_ct McD McD - - McD McD McD McD McD McD xv_ctr CcD CcD - - - - + + + + xv_trr McD McD - + + + - + + + xv_ctrr CcD CcD - - + + + + + + clv_t CcD CcD - CcD CcD CcD - CcD CcD CcD clv_ct CcD CcD - - CcD CcD CcD CcD CcD CcD clv_ctr CcD CcD - - - - + + + + cxv_t CcD CcD - CcD CcD CcD - CcD CcD CcD cxv_ct CcD CcD - - CcD CcD CcD CcD CcD CcD cxv_ctr CcD CcD - - - - + + + + cxv_ctrr CcD CcD - - + + + + + + */ 

std :: рдЪрд╛рд▓ рдпрд╛ std :: рдЖрдЧреЗ рд╕реЗ рд╕реНрдерд╛рдиреАрдп рд╡рд╕реНрддреБрдУрдВ рдкрд░ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрдм рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рд▓реМрдЯрддреЗ рд╣реИрдВ, рдпрджрд┐ рд░рд┐рдЯрд░реНрди рд╡реИрд▓реНрдпреВ рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬрд╝реЗрд╢рди (RVO) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рд╕реА рд╕реНрдерд╛рдиреАрдп рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдорд╛рди рджреНрд╡рд╛рд░рд╛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ - рдХреНрдпреЛрдВрдХрд┐ LV рдХреЛ XV рдореЗрдВ рдХрдирд╡рд░реНрдЯ рдХрд░рдиреЗ рд╕реЗ рдХрдВрдкрд╛рдЗрд▓рд░ рдХреЛ RVO рд▓рдЧрд╛рдиреЗ рд╕реЗ рд░реЛрдХрд╛ рдЬрд╛ рд╕рдХреЗрдЧрд╛ рдФрд░ рдмрджрд▓реЗ рд╡рд╕реНрддреБред рдЬрдм рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЖрд░рд╡реАрдУ рдЕрдзрд┐рдХ рдкреНрд░рднрд╛рд╡реА рд╣реЛрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдХрд┐рд╕реА рднреА рдЕрддрд┐рд░рд┐рдХреНрдд рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ / рдЪрд╛рд▓ рдирд┐рд░реНрдорд╛рдгрдХрд░реНрддрд╛рдУрдВ рдпрд╛ рдСрдкрд░реЗрдЯрд░реЛрдВ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рд╕реЗ рдмрдЪрддрд╛ рд╣реИред


рджреВрд╕рд░реА рдУрд░, рд╡рд┐рднрд┐рдиреНрди рд╕рдВрдХрд▓рдХ рд╡рд┐рднрд┐рдиреНрди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ рдЖрд░рд╡реАрдУ рдХреЛ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЬреНрдпрд╛рджрд╛рддрд░ рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ рд╕рдВрдХрд▓рдХ рдХрдо рд╕реЗ рдХрдо рдЪрд╛рд▓ рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ рдСрдкрд░реЗрдЯрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдВрдЧреЗред рдпрджрд┐ рдХреЛрдИ рдЬреЛрдЦрд┐рдо рд╣реИ рдХрд┐ рдХреЙрдкреА рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ рдЖрд░рд╡реАрдУ рдХреЗ рдмрдЬрд╛рдп рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рддреЛ рдЖрдк std :: move рдпрд╛ std :: рдлреЙрд░рд╡рд░реНрдб рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рд░рд┐рдЯрд░реНрди рдлреЙрд░ рд╡реИрд▓реНрдпреВ рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЬрд╣рд╛рдВ рддрдХ тАЛтАЛрдореБрдЭреЗ рдПрдХрдорд╛рддреНрд░ рд╕реНрдерд┐рддрд┐ рдкрддрд╛ рд╣реИ рдЬрдм рдРрд╕рд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдЬрдм рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реЛ рд╡рд╛рдкрд╕реА рд╡рд┐рд╡рд░рдгреА рдореЗрдВ рд╡рд┐рд╡рд░рдгреА рдкрд░рд┐рдЪрд╛рд▓рдХ return param ? a : b , рдЬрд┐рд╕реЗ рдЖрдорддреМрд░ рдкрд░ рд╕реНрдЯреЗрдЯрдореЗрдВрдЯ рдХреЗ рд╕рд╛рде рдЖрд╕рд╛рдиреА рд╕реЗ рдмрджрд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЖрдк рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреМрди рд╕реЗ рд╕рдВрдХрд▓рдХ рдЖрд░рд╡реАрдУ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐рди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ https: // рдпрд╣рд╛рдБ рдФрд░ https: // рдпрд╣рд╛рдБред


рдЙрдмрдВрдЯреВ рдкрд░ рдирд╡реАрдирддрдо рдХреНрд▓реИрдВрдЧ рдХреЗ рд╕рд╛рде рдЖрд░рд╡реАрдУ рдХрд╛ рдкрд░реАрдХреНрд╖рдг (рд╡рд░реНрд╖ 2019):


рдкреНрд░рддреНрдпреЗрдХ рдирд┐рд░реНрдорд╛рддрд╛ рдФрд░ рдСрдкрд░реЗрдЯрд░ рдХреЗ рдореБрджреНрд░рдг рдХреЗ рд╕рд╛рде рдЙрджрд╛рд╣рд░рдг рдФрд░ рдкрд░реАрдХреНрд╖рдг
 #include <iostream> #include <string> #include <iomanip> using namespace std; void report(string st) { cout << st << " "; } struct T { T() { report("Dc"); } T(int va) : a(va) { report("Pc"); } T(const T& other) : a(other.a) { report("Cc"); } T(T&& other) : a(std::exchange(other.a, 0)) { report("Mc"); } T& operator=(int va) { report("Va"); a = va; return *this; } T& operator=(const T& rhs) { report("Ca"); // check for self-assignment if(&rhs == this) return *this; a = rhs.a; return *this; } T& operator=(T&& rhs) { report("Ma"); // check for self-assignment if(&rhs == this) return *this; a = std::exchange(rhs.a, 0); return *this; } ~T() { report("D"); } int a = 1; }; T urvo_single() { //const bool param = true; return T(); } T urvo_two() { const bool param = true; if(param) return T(); else return T(); } T urvo_two_with_param(bool param) { if(param) return T(); else return T(); } T urvo_with_exception_1(bool param) { if(!param) throw std::exception(); return T(); } T urvo_with_exception_2(bool param) { if(param) return T(); else throw std::exception(); } T urvo_with_exception_3() { const bool param = true; if(param) return T(); else throw std::exception(); } static T make_X() { return T(); } T rrvo_single() { //const bool param = true; return make_X(); } T rrvo_two() { const bool param = true; if(param) return make_X(); else return make_X(); } T rrvo_two_with_param(bool param) { if(param) return make_X(); else return make_X(); } T rrvo_with_exception_1(bool param) { if(!param) throw std::exception(); return make_X(); } T rrvo_with_exception_2(bool param) { if(param) return make_X(); else throw std::exception(); } T rrvo_with_exception_3() { const bool param = true; if(param) return make_X(); else throw std::exception(); } T nrvo_single_1() { T a; return a; } T nrvo_single_2() { { T a; return a; } } T nrvo_single_with_exception_1(bool param) { T a; if(!param) throw std::exception(); return a; } T nrvo_single_with_exception_1a(bool param) { if(!param) throw std::exception(); T a; return a; } T nrvo_single_with_exception_2(bool param) { T a; if(param) return a; else throw std::exception(); // Silence compilation error, does not count as an additional // return statement as it is unreachable code return a; } T nrvo_single_with_exception_2a(bool param) { if(param) { T a; return a; } else throw std::exception(); } T nrvo_single_with_exception_3() { const bool param = true; T a; if(param) return a; else throw std::exception(); } T nrvo_single_with_exception_3a() { const bool param = true; if(param) { T a; return a; } else throw std::exception(); } T nrvo_two_different_tern() { const bool param = true; T a, b; return param ? a : b; } T nrvo_two_different_if() { const bool param = true; T a, b; if(param) return a; else return b; } T nrvo_two_different_if_2() { const bool param = true; if(param) { T a; return a; } else { T b; return b; } } T nrvo_two_different_with_param_tern(bool param) { T a, b; return param ? a : b; } T nrvo_two_different_with_param_if(bool param) { T a, b; if(param) return a; else return b; } T nrvo_two_different_with_param_if_2(bool param) { if(param) { T a; return a; } else { T b; return b; } } T nrvo_two_equal_tern() { const bool param = true; T a; return param ? a : a; } T nrvo_two_equal_if() { const bool param = true; T a; if(param) return a; else return a; } T nrvo_two_equal_with_param_tern(bool param) { T a; return param ? a : a; } T nrvo_two_equal_with_param_if(bool param) { T a; if(param) return a; else return a; } T nrvo_urvo_mixed_static() { static const bool param = true; if (param) return T(); T a; return a; } T nrvo_urvo_mixed_dynamic(bool param) { if (param) return T(); T a; return a; } void print_col(const string &st, int width) { cout << endl << left << setw(width) << st; } #define CHECK_COPIES(stmt) { \ print_col(#stmt ": ", 20); \ try { \ stmt; \ } \ catch(...) { \ } \ } \ int main() { CHECK_COPIES( T a = urvo_single()); CHECK_COPIES( T a = urvo_two()); CHECK_COPIES( T a = urvo_two_with_param(true)); CHECK_COPIES( T a = urvo_with_exception_1(true)); CHECK_COPIES( T a = urvo_with_exception_2(true)); CHECK_COPIES( T a = urvo_with_exception_3()); cerr << " "; CHECK_COPIES( T a = rrvo_single()); CHECK_COPIES( T a = rrvo_two()); CHECK_COPIES( T a = rrvo_two_with_param(true)); CHECK_COPIES( T a = rrvo_with_exception_1(true)); CHECK_COPIES( T a = rrvo_with_exception_2(true)); CHECK_COPIES( T a = rrvo_with_exception_3()); cerr << " "; CHECK_COPIES( T a = nrvo_single_1()); CHECK_COPIES( T a = nrvo_single_2()); CHECK_COPIES( T a = nrvo_single_with_exception_1(true)); CHECK_COPIES( T a = nrvo_single_with_exception_1a(true)); CHECK_COPIES( T a = nrvo_single_with_exception_2(true)); CHECK_COPIES( T a = nrvo_single_with_exception_2a(true)); CHECK_COPIES( T a = nrvo_single_with_exception_3()); CHECK_COPIES( T a = nrvo_single_with_exception_3a()); cerr << " "; CHECK_COPIES( T a = nrvo_two_different_tern()); CHECK_COPIES( T a = nrvo_two_different_if()); CHECK_COPIES( T a = nrvo_two_different_if_2()); CHECK_COPIES( T a = nrvo_two_different_with_param_tern(true)); CHECK_COPIES( T a = nrvo_two_different_with_param_if(true)); CHECK_COPIES( T a = nrvo_two_different_with_param_if_2(true)); CHECK_COPIES( T a = nrvo_two_equal_tern()); CHECK_COPIES( T a = nrvo_two_equal_if()); CHECK_COPIES( T a = nrvo_two_equal_with_param_tern(true)); CHECK_COPIES( T a = nrvo_two_equal_with_param_if(true)); cerr << " "; CHECK_COPIES( T a = nrvo_urvo_mixed_static()); CHECK_COPIES( T a = nrvo_urvo_mixed_dynamic(true)); } /* Output: T a = urvo_single(): Dc D T a = urvo_two(): Dc D T a = urvo_two_with_param(true): Dc D T a = urvo_with_exception_1(true): Dc D T a = urvo_with_exception_2(true): Dc D T a = urvo_with_exception_3(): Dc D T a = rrvo_single(): Dc D T a = rrvo_two(): Dc D T a = rrvo_two_with_param(true): Dc D T a = rrvo_with_exception_1(true): Dc D T a = rrvo_with_exception_2(true): Dc D T a = rrvo_with_exception_3(): Dc D T a = nrvo_single_1(): Dc D T a = nrvo_single_2(): Dc D T a = nrvo_single_with_exception_1(true): Dc D T a = nrvo_single_with_exception_1a(true): Dc D T a = nrvo_single_with_exception_2(true): Dc D T a = nrvo_single_with_exception_2a(true): Dc D T a = nrvo_single_with_exception_3(): Dc D T a = nrvo_single_with_exception_3a(): Dc D T a = nrvo_two_different_tern(): Dc Dc Cc DDD T a = nrvo_two_different_if(): Dc Dc Mc DDD T a = nrvo_two_different_if_2(): Dc D T a = nrvo_two_different_with_param_tern(true): Dc Dc Cc DDD T a = nrvo_two_different_with_param_if(true): Dc Dc Mc DDD T a = nrvo_two_different_with_param_if_2(true): Dc D T a = nrvo_two_equal_tern(): Dc Cc DD T a = nrvo_two_equal_if(): Dc D T a = nrvo_two_equal_with_param_tern(true): Dc Cc DD T a = nrvo_two_equal_with_param_if(true): Dc D T a = nrvo_urvo_mixed_static(): Dc D T a = nrvo_urvo_mixed_dynamic(true): Dc D */ 

Links:


Copy elision
Copy elision revisited
Compare clang and gcc copy elision (tests with similar results are commented out)


Passing and returning trivially copyable objects of small size


Trivially copyable struct or class:


  • has no virtual members or virtual base classes
  • has default copy and move constructors and operators

Trivially copyable objects of small size (up to 16 bytes) can be passed in CPU registers when passed to function by value тАФ like scalar types.


Also, when passing it by value, compiler has additional guarantee that object will not change during the course of the function even if other functions are called тАФ this is why compiler can generate more effective code in this situations. If passed by const T&, there is no such guarantee, because object passed by constant reference can still be changed from other function, or multiple passed objects can use shared memory.


For the same reason, std::string_view should be passed by value.


Links:


Trivially copyable


Returning from a function with a reference parameter


A reference to an object can be passed to a function so that function can change source object:


 T& change(T& X) { X.change(); return X; } 

This method should not be used if temporary object can be created inside function and returned by value, because returning by value can take advantage of return value optimization (see above).


Passing multiple parameters and returning one of them from function


If all passed parameters are lvalues, you can pass and return by const T&. This gives high performance, because no copy/move constructors or operators are called:


 const T& get(const T& a, const T& b) { if ( /* something */ ) return a; else return b; } 

prvalue cannot be passed to get function, because this would result in returning a reference to a temporary object. If prvalue has to be passed,


If both parameters are temporary objects (prvalues), T&& can be returned, which also gives high performance (no copy/move constructors or operators are called):


 T&& get(T&& a, T&& b) { if ( /* something */ ) return std::move(a); else return std::move(b); } 

If some of parameters are temporary objects (prvalues) and other are lvalues, it is difficult to high performance without complicating the function interface. In the following example if lvalue and prvalue are passed as A and B arguments into the function, copy constructor will be called if A is chosen and move constructor if B is chosen:


 T get(const T& a, T&& b) { if ( /* something */ ) return a; else return std::move(b); } 

Passing to constructor or setter


In this section I describe passing an object of type T to an object of type C during construction of type C or by calling a setter:


 class C { C(TX) : x(X) {} void set(TX) { x = X; } T x; }; T y; C c(y); c.set(y); 

  • For copying an lvalue to x member variable in an object of class C:
    • with class C constructor: any of the following variants is good ("T move" variant is a bit less efficient due to calling an additional move constructor)
    • with class C set(T):
    • if T is copy-on-write (like CString in MFC/ATL) and x will not change later, any of the following variants is good ("T move" variant is a bit less efficient due to calling an additional move constructor)
    • if T is not copy-on write or x can change later, "T move" variant becomes inefficient, because it does not allow to avoid deallocation, even if already allocated memory in existing object x is enough for new object and class can reuse allocated memory (like std::string)
  • For moving an xvalue or prvalue to x member variable in an object of class C with C's constructor or C's set member function any of the following variants is good except "const T&" (because it requires copying). Perfect forwarding has a slight performance advantage due to avoiding calling move constructor when converting from different type, instead forwarding parameter of a different type to a parametrized constructor

Variants:


  • const T& тАФ optimal if we do not need to move objects or store them in dynamically growing containers
     class C { C(const T& X) : x(X) {} void set(const T& X) { x = X; } T x; }; 
  • const T& + T&& move тАФ optimized variant if we need to support both lvalue copy and rvalue move. Can lead to code duplication, especially if constructors with different combinations of & and && are needed. Provides simple implementation of noexcept for effective use with containers.
     class C { C(const T& X) : x(X) {} C(T&& X) : x(std::move(X)) {} void set(const T& X) { x = X; } void set(T&& X) { x = std::move(X); } T x; }; 
  • T move тАФ looks simple, but not very intuitive (can avoid copying and change object, passed with std::move as xvalue). Less efficient than perfect forwarding and &+&& in some situations (does not allow to avoid deallocation, even if already allocated memory in existing object x is enough for new object and class can reuse allocated memory, calls excessive moves and destructors)
     class C { C(TX) : x(std::move(X)) {} void set(TX) { x = std::move(X); } T x; }; 
  • Perfect forwarding (PF) тАФ most effective variant (especially when forwarding literals or other types, which can be converted to class with parametrized constructors), but it is more difficult to write, which increases risk of mistakes. Does not support virtual functions and has to be implemented in header file.
     class C { template<typename Z> C(Z&& X) : x(std::forward<Z>(X)) {} template<typename Z> void set(Z&& X) { x = std::forward<Z>(X); } T x; }; 
  • Strict perfect forwarding (PF Strict). Has same qualities as perfect forwarding, but is more safe, because it does not allow to convert types and thus cannot receive literals (actually, it is the only variant among discussed in this section, which does not allow to convert types).
     class C { template<class Z, class=std::enable_if_t<std::is_same<std::decay_t<Z>, T>::value>> C(Z&& X) : x(std::forward<Z>(X)) {} template<class Z, class=std::enable_if_t<std::is_same<std::decay_t<Z>, T>::value>> void set(Z&& X) { x = std::forward<Z>(X); } T x; }; 


In the comparison tables below constructor properties are highlighted with green, setter member function properties are highlighted with yellow.



Annotations:
1 тАФ Becomes combinatorial if constructor has multiple parameters
2 тАФ Function is technically noexcept, but copy before function call can result in exception
3 тАФ Requires noexcept(std::is_nothrow_assignable<Type&, T>::value)
4 тАФ Does not accept conversion
5 тАФ Unconditional deallocation leads to inability to reuse allocated storage (std::string). Not a problem for copy-on-write implementations (Tstring)
6 тАФ If you do not have overloaded assignment operator for value type in object class, this will be: VcMaD


Examples and tests of variants with printing of used copy/move constructors and operators:


Examples and tests with printing of each called constructor and operator
 #include <iostream> using namespace std; struct TStruct { TStruct() { cout << "Dc"; } TStruct(int va) : a(va) { cout << "Vc"; } TStruct(const TStruct& other) : a(other.a) { cout << "Cc"; } TStruct(TStruct&& other) : a(std::exchange(other.a, 0)) { cout << "Mc"; } TStruct& operator=(int va) { cout << "Va"; a = va; return *this; } TStruct& operator=(const TStruct& rhs) { cout << "Ca"; // check for self-assignment if(&rhs == this) return *this; a = rhs.a; return *this; } TStruct& operator=(TStruct&& rhs) { cout << "Ma"; // check for self-assignment if(&rhs == this) return *this; a = std::exchange(rhs.a, 0); return *this; } ~TStruct() { cout << "D"; } int a = 1; }; struct TRef { TRef(TStruct& tsv) : ts(tsv) {} void set(TStruct& tsv) { ts = tsv; } TStruct ts; }; struct TConstRef { TConstRef(const TStruct& tsv) : ts(tsv) {} void set(const TStruct& tsv) { ts = tsv; } TStruct ts; }; struct TConstRefAndRvalueRef { TConstRefAndRvalueRef(const TStruct& tsv) : ts(tsv) { cout << "Lr"; } TConstRefAndRvalueRef(TStruct&& tsv) : ts(std::move(tsv)) { cout << "Rr"; } void set(const TStruct& tsv) { cout << "Sl"; ts = tsv; } void set(TStruct&& tsv) { cout << "Sr"; ts = std::move(tsv); } TStruct ts; }; struct TConstRvalueRef { TConstRvalueRef(const TStruct&& tsv) : ts(std::move(tsv)) { } void set(const TStruct&& tsv) { ts = std::move(tsv); } TStruct ts; }; struct TValueMove { TValueMove(TStruct tsv) : ts(std::move(tsv)) {} void set(TStruct tsv) { ts = std::move(tsv); } TStruct ts; }; struct TConstValueMove { TConstValueMove(const TStruct tsv) : ts(std::move(tsv)) {} void set(const TStruct tsv) { ts = std::move(tsv); } TStruct ts; }; struct TPerfectForward { template<class T> TPerfectForward(T&& tsv) : ts(std::forward<T>(tsv)) {} template<class T> void set(T&& tsv) { ts = std::forward<T>(tsv); } TStruct ts; }; struct TConstPerfectForward { template<class T> TConstPerfectForward(const T&& tsv) : ts(std::forward<T>(tsv)) {} template<class T> void set(const T&& tsv) { ts = std::forward<T>(tsv); } TStruct ts; }; struct TPerfectForwardStrict { template<class T, class=std::enable_if_t<std::is_same<std::decay_t<T>, TStruct>::value>> TPerfectForwardStrict(T&& tsv) : ts(std::forward<T>(tsv)) {} template<class T, class=std::enable_if_t<std::is_same<std::decay_t<T>, TStruct>::value>> void set(T&& tsv) { ts = std::forward<T>(tsv); } TStruct ts; }; struct TMultiVariant { TMultiVariant(const TStruct& tsv) : ts(tsv) { cout << "Lr"; } TMultiVariant(TStruct&& tsv) : ts(std::move(tsv)) { cout << "Rr"; } void set(const TStruct& tsv) { cout << "Sl"; ts = tsv; } void set(TStruct&& tsv) { cout << "Sr"; ts = std::move(tsv); } template<class T> TMultiVariant(T&& tsv) : ts(std::forward<T>(tsv)) { cout << "Pf"; } template<class T> void set(T&& tsv) { cout << "Sp"; ts = std::forward<T>(tsv); } TStruct ts; }; struct TMultiVariantStrict { TMultiVariantStrict(const TStruct& tsv) : ts(tsv) { cout << "Lr"; } TMultiVariantStrict(TStruct&& tsv) : ts(std::move(tsv)) { cout << "Rr"; } void set(const TStruct& tsv) { cout << "Sl"; ts = tsv; } void set(TStruct&& tsv) { cout << "Sr"; ts = std::move(tsv); } template<class T, class=std::enable_if_t<std::is_same<std::decay_t<T>, TStruct>::value>> TMultiVariantStrict(T&& tsv) : ts(std::forward<T>(tsv)) { cout << "Pf"; } template<class T, class=std::enable_if_t<std::is_same<std::decay_t<T>, TStruct>::value>> void set(T&& tsv) { cout << "Sp"; ts = std::forward<T>(tsv); } TStruct ts; }; TStruct get_st() { return TStruct(7); } void detect_change(int& param, int val) { if (param != val) { cout << "!"; param = val; } else { cout << "-"; } } void test_passing() { cout << "TStruct st(100): "; TStruct st(100); // Test constructing with object cout << endl << "TRef (st): "; TRef rf(st); detect_change(st.a, 100); cout << endl << "TConstRef (st): "; TConstRef crf(st); detect_change(st.a, 100); cout << endl << "TConstRefAndRvalueRef (st): "; TConstRefAndRvalueRef crf_rvf(st); detect_change(st.a, 100); // Will not compile // cout << endl << "TConstRvalueRef (st): "; // TConstRvalueRef crvf(st); // detect_change(st.a, 100); cout << endl << "TValueMove (st): "; TValueMove vm(st); detect_change(st.a, 100); cout << endl << "TConstValueMove (st): "; TConstValueMove cvm(st); detect_change(st.a, 100); cout << endl << "TPerfectForward (st): "; TPerfectForward pf(st); detect_change(st.a, 100); // Will not compile // cout << endl << "TConstPerfectForward (st): "; // TConstPerfectForward cpf(st); // detect_change(st.a, 100); cout << endl << "TPerfectForwardStrict (st): "; TPerfectForwardStrict pft(st); detect_change(st.a, 100); cout << endl << "TMultiVariant (st): "; TMultiVariant mv(st); detect_change(st.a, 100); cout << endl << "TMultiVariantStrict (st): "; TMultiVariantStrict mvt(st); detect_change(st.a, 100); // Test constructing with moved object // Will not compile because of std::move // cout << endl << "TRef (std::move(st)): "; // TRef rf4(std::move(st)); // detect_change(st.a, 100); cout << endl << "TConstRef (std::move(st)): "; TConstRef crf4(std::move(st)); detect_change(st.a, 100); cout << endl << "TConstRefAndRvalueRef (std::move(st)): "; TConstRefAndRvalueRef crf_rvf4(std::move(st)); detect_change(st.a, 100); cout << endl << "TConstRvalueRef (std::move(st)): "; TConstRvalueRef crvf4(std::move(st)); detect_change(st.a, 100); cout << endl << "TValueMove (std::move(st)): "; TValueMove vm4(std::move(st)); detect_change(st.a, 100); cout << endl << "TConstValueMove (std::move(st)): "; TConstValueMove cvm4(std::move(st)); detect_change(st.a, 100); cout << endl << "TPerfectForward (std::move(st)): "; TPerfectForward pf4(std::move(st)); detect_change(st.a, 100); // Will not compile // cout << endl << "TConstPerfectForward (std::move(st)): "; // TConstPerfectForward cpf4(std::move(st)); // detect_change(st.a, 100); cout << endl << "TPerfectForwardStrict (std::move(st)): "; TPerfectForwardStrict pft4(std::move(st)); detect_change(st.a, 100); cout << endl << "TMultiVariant (std::move(st)): "; TMultiVariant mv4(std::move(st)); detect_change(st.a, 100); cout << endl << "TMultiVariantStrict (std::move(st)): "; TMultiVariantStrict mvt4(std::move(st)); detect_change(st.a, 100); // Test constructing with temporary object // Will not compile // cout << endl << "TRef (TStruct(6)): "; // TRef rf3(TStruct(6)); cout << endl << "TConstRef (TStruct(6)): "; TConstRef crf3(TStruct(6)); cout << endl << "TConstRefAndRvalueRef (TStruct(6)): "; TConstRefAndRvalueRef crf_rvf3(TStruct(6)); cout << endl << "TConstRvalueRef (TStruct(6)): "; TConstRvalueRef crvf3(TStruct(6)); cout << endl << "TValueMove (TStruct(6)): "; TValueMove vm3(TStruct(6)); cout << endl << "TConstValueMove (TStruct(6)): "; TConstValueMove cvm3(TStruct(6)); cout << endl << "TPerfectForward (TStruct(6)): "; TPerfectForward pf3(TStruct(6)); // Will not compile //cout << endl << "TConstPerfectForward (TStruct(6)): "; //TConstPerfectForward cpf3(TStruct(6)); cout << endl << "TPerfectForwardStrict (TStruct(6)): "; TPerfectForwardStrict pft3(TStruct(6)); cout << endl << "TMultiVariant (TStruct(6)): "; TMultiVariant mv3(TStruct(6)); cout << endl << "TMultiVariantStrict (TStruct(6)): "; TMultiVariantStrict mvt3(TStruct(6)); // Test constructing with RVO object // Will not compile //cout << endl << "TRef (get_st()): "; //TRef rf5(get_st()); cout << endl << "TConstRef (get_st()): "; TConstRef crf5(get_st()); cout << endl << "TConstRefAndRvalueRef (get_st()): "; TConstRefAndRvalueRef crf_rvf5(get_st()); cout << endl << "TConstRvalueRef (get_st()): "; TConstRvalueRef crvf5(get_st()); cout << endl << "TValueMove (get_st()): "; TValueMove vm5(get_st()); cout << endl << "TConstValueMove (get_st()): "; TConstValueMove cvm5(get_st()); cout << endl << "TPerfectForward (get_st()): "; TPerfectForward pf5(get_st()); //cout << endl << "TConstPerfectForward (get_st()): "; //TConstPerfectForward cpf5(get_st()); cout << endl << "TPerfectForwardStrict (get_st()): "; TPerfectForwardStrict pft5(get_st()); cout << endl << "TMultiVariant (get_st()): "; TMultiVariant mv5(get_st()); cout << endl << "TMultiVariantStrict (get_st()): "; TMultiVariantStrict mvt5(get_st()); // Test constructing with literal // Will not compile //cout << endl << "TRef (5): "; //TRef rf2(5); cout << endl << "TConstRef (5): "; TConstRef crf2(5); cout << endl << "TConstRefAndRvalueRef (5): "; TConstRefAndRvalueRef crf_rvf2(5); cout << endl << "TConstRvalueRef (5): "; TConstRvalueRef crvf2(5); cout << endl << "TValueMove (5): "; TValueMove vm2(5); cout << endl << "TConstValueMove (5): "; TConstValueMove cvm2(5); cout << endl << "TPerfectForward (5): "; TPerfectForward pf2(5); // Will not compile //cout << endl << "TConstPerfectForward (5): "; //TConstPerfectForward cpf2(5); // Will not compile due to SFINAE test //cout << endl << "TPerfectForwardStrict (5): "; //TPerfectForwardStrict pft2(5); cout << endl << "TMultiVariant (5): "; TMultiVariant mv2(5); cout << endl << "TMultiVariantStrict (5): "; TMultiVariantStrict mvt2(5); // Test setting with object st.a = 100; cout << endl << "TRef set(st): "; rf.set(st); detect_change(st.a, 100); cout << endl << "TConstRef set(st): "; crf.set(st); detect_change(st.a, 100); cout << endl << "TConstRefAndRvalueRef set(st): "; crf_rvf.set(st); detect_change(st.a, 100); // Will not compile // cout << endl << "TConstRvalueRef set(st): "; // crvf2.set(st); // detect_change(st.a, 100); cout << endl << "TValueMove set(st): "; vm.set(st); detect_change(st.a, 100); cout << endl << "TConstValueMove set(st): "; cvm.set(st); detect_change(st.a, 100); cout << endl << "TPerfectForward set(st): "; pf.set(st); detect_change(st.a, 100); cout << endl << "TPerfectForwardStrict set(st): "; pft.set(st); detect_change(st.a, 100); cout << endl << "TMultiVariant set(st): "; mv.set(st); detect_change(st.a, 100); cout << endl << "TMultiVariantStrict set(st): "; mvt.set(st); detect_change(st.a, 100); // Test setting with moved object // Will not compile //cout << endl << "TRef set(std::move(st)): "; //rf.set(std::move(st)); //detect_change(st.a, 100); cout << endl << "TConstRef set(std::move(st)): "; crf.set(std::move(st)); detect_change(st.a, 100); cout << endl << "TConstRefAndRvalueRef set(std::move(st)): "; crf_rvf.set(std::move(st)); detect_change(st.a, 100); cout << endl << "TConstRvalueRef set(std::move(st)): "; crvf2.set(std::move(st)); detect_change(st.a, 100); cout << endl << "TValueMove set(std::move(st)): "; vm.set(std::move(st)); detect_change(st.a, 100); cout << endl << "TConstValueMove set(std::move(st)): "; cvm.set(std::move(st)); detect_change(st.a, 100); cout << endl << "TPerfectForward set(std::move(st)): "; pf.set(std::move(st)); detect_change(st.a, 100); detect_change(st.a, 100); cout << endl << "TPerfectForwardStrict set(std::move(st)): "; pft.set(std::move(st)); detect_change(st.a, 100); cout << endl << "TMultiVariant set(std::move(st)): "; mv.set(std::move(st)); detect_change(st.a, 100); cout << endl << "TMultiVariantStrict set(std::move(st)): "; mvt.set(std::move(st)); detect_change(st.a, 100); // Test setting with constructed temporary object // Will not compile //cout << endl << "TRef set(TStruct(8)): "; //rf.set(TStruct(8)); cout << endl << "TConstRef set(TStruct(8)): "; crf.set(TStruct(8)); cout << endl << "TConstRefAndRvalueRef set(TStruct(8)): "; crf_rvf.set(TStruct(8)); cout << endl << "TConstRvalueRef set(TStruct(8)): "; crvf2.set(TStruct(8)); cout << endl << "TValueMove set(TStruct(8)): "; vm.set(TStruct(8)); cout << endl << "TConstValueMove set(TStruct(8)): "; cvm.set(TStruct(8)); cout << endl << "TPerfectForward set(TStruct(8)): "; pf.set(TStruct(8)); cout << endl << "TPerfectForwardStrict set(TStruct(8)): "; pft.set(TStruct(8)); cout << endl << "TMultiVariant set(TStruct(8)): "; mv.set(TStruct(8)); cout << endl << "TMultiVariantStrict set(TStruct(8)): "; mvt.set(TStruct(8)); // Test setting with RVO object // Will not compile //cout << endl << "TRef set(get_st()): "; //rf.set(get_st()); cout << endl << "TConstRef set(get_st()): "; crf.set(get_st()); cout << endl << "TConstRefAndRvalueRef set(get_st()): "; crf_rvf.set(get_st()); cout << endl << "TConstRvalueRef set(get_st()): "; crvf2.set(get_st()); cout << endl << "TValueMove set(get_st()): "; vm.set(get_st()); cout << endl << "TConstValueMove set(get_st()): "; cvm.set(get_st()); cout << endl << "TPerfectForward set(get_st()): "; pf.set(get_st()); cout << endl << "TPerfectForwardStrict set(get_st()): "; pft.set(get_st()); cout << endl << "TMultiVariant set(get_st()): "; mv.set(get_st()); cout << endl << "TMultiVariantStrict set(get_st()): "; mvt.set(get_st()); cout << endl << "st = 3: "; st = 3; // Test setting with literal // Will not compile //cout << endl << "TRef set(4): "; //rf.set(4); cout << endl << "TConstRef set(4): "; crf.set(4); cout << endl << "TConstRefAndRvalueRef set(4): "; crf_rvf.set(4); cout << endl << "TConstRvalueRef set(4): "; crvf2.set(4); cout << endl << "TValueMove set(4): "; vm.set(4); cout << endl << "TConstValueMove set(4): "; cvm.set(4); cout << endl << "TPerfectForward set(4): "; pf.set(4); // Will not compile due to SFINAE test //cout << endl << "TPerfectForwardStrict set(st): "; //pft.set(4); cout << endl << "TMultiVariant set(4): "; mv.set(4); cout << endl << "TMultiVariantStrict set(4): "; mvt.set(4); cout << endl; } int main() { test_passing(); return 0; } /* Output: TStruct st(100): Vc TRef (st): Cc- TConstRef (st): Cc- TConstRefAndRvalueRef (st): CcLr- TValueMove (st): CcMcD- TConstValueMove (st): CcCcD- TPerfectForward (st): Cc- TPerfectForwardStrict (st): Cc- TMultiVariant (st): CcPf- TMultiVariantStrict (st): CcPf- TConstRef (std::move(st)): Cc- TConstRefAndRvalueRef (std::move(st)): McRr! TConstRvalueRef (std::move(st)): Cc- TValueMove (std::move(st)): McMcD! TConstValueMove (std::move(st)): McCcD! TPerfectForward (std::move(st)): Mc! TPerfectForwardStrict (std::move(st)): Mc! TMultiVariant (std::move(st)): McRr! TMultiVariantStrict (std::move(st)): McRr! TConstRef (TStruct(6)): VcCcD TConstRefAndRvalueRef (TStruct(6)): VcMcRrD TConstRvalueRef (TStruct(6)): VcCcD TValueMove (TStruct(6)): VcMcD TConstValueMove (TStruct(6)): VcCcD TPerfectForward (TStruct(6)): VcMcD TPerfectForwardStrict (TStruct(6)): VcMcD TMultiVariant (TStruct(6)): VcMcRrD TMultiVariantStrict (TStruct(6)): VcMcRrD TConstRef (get_st()): VcCcD TConstRefAndRvalueRef (get_st()): VcMcRrD TConstRvalueRef (get_st()): VcCcD TValueMove (get_st()): VcMcD TConstValueMove (get_st()): VcCcD TPerfectForward (get_st()): VcMcD TPerfectForwardStrict (get_st()): VcMcD TMultiVariant (get_st()): VcMcRrD TMultiVariantStrict (get_st()): VcMcRrD TConstRef (5): VcCcD TConstRefAndRvalueRef (5): VcMcRrD TConstRvalueRef (5): VcCcD TValueMove (5): VcMcD TConstValueMove (5): VcCcD TPerfectForward (5): Vc TMultiVariant (5): VcPf TMultiVariantStrict (5): VcMcRrD TRef set(st): Ca- TConstRef set(st): Ca- TConstRefAndRvalueRef set(st): SlCa- TValueMove set(st): CcMaD- TConstValueMove set(st): CcCaD- TPerfectForward set(st): Ca- TPerfectForwardStrict set(st): Ca- TMultiVariant set(st): SpCa- TMultiVariantStrict set(st): SpCa- TConstRef set(std::move(st)): Ca- TConstRefAndRvalueRef set(std::move(st)): SrMa! TConstRvalueRef set(std::move(st)): Ca- TValueMove set(std::move(st)): McMaD! TConstValueMove set(std::move(st)): McCaD! TPerfectForward set(std::move(st)): Ma!- TPerfectForwardStrict set(std::move(st)): Ma! TMultiVariant set(std::move(st)): SrMa! TMultiVariantStrict set(std::move(st)): SrMa! TConstRef set(TStruct(8)): VcCaD TConstRefAndRvalueRef set(TStruct(8)): VcSrMaD TConstRvalueRef set(TStruct(8)): VcCaD TValueMove set(TStruct(8)): VcMaD TConstValueMove set(TStruct(8)): VcCaD TPerfectForward set(TStruct(8)): VcMaD TPerfectForwardStrict set(TStruct(8)): VcMaD TMultiVariant set(TStruct(8)): VcSrMaD TMultiVariantStrict set(TStruct(8)): VcSrMaD TConstRef set(get_st()): VcCaD TConstRefAndRvalueRef set(get_st()): VcSrMaD TConstRvalueRef set(get_st()): VcCaD TValueMove set(get_st()): VcMaD TConstValueMove set(get_st()): VcCaD TPerfectForward set(get_st()): VcMaD TPerfectForwardStrict set(get_st()): VcMaD TMultiVariant set(get_st()): VcSrMaD TMultiVariantStrict set(get_st()): VcSrMaD st = 3: Va TConstRef set(4): VcCaD TConstRefAndRvalueRef set(4): VcSrMaD TConstRvalueRef set(4): VcCaD TValueMove set(4): VcMaD TConstValueMove set(4): VcCaD TPerfectForward set(4): Va TMultiVariant set(4): SpVa TMultiVariantStrict set(4): VcSrMaD DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD */ 

Links:
CppCon 2014: Herb Sutter "Back to the Basics! Essentials of Modern C++ Style"
PDF presentation
Meaning of acronym SSO in the context of std::string
Why is value taking setter member functions not recommended in Herb Sutter's CppCon 2014 talk (Back to Basics: Modern C++ Style)?
What's the correct enable_if constraint on perfect forwarding setter?
Beware of Perfect Forwarding Constructors


Why other variants of passing to constructor or setter are less used


  • T& тАФ cannot accept rvalue. Is the same as "const T&" variant, but less safe.
     class T { C(T& X) : x(X) {} void set(T& X) { x = X; } T x; }; 
  • const T&& move тАФ does not allow move due to prohibiting change of passed object. Not used.
     class C { C(const T&& X) : x(std::move(X)) {} void set(const T&& X) { x = std::move(X); } T x; }; 
  • const T move тАФ does not allow move due to prohibiting change of passed object.
     class C { C(const TX) : x(std::move(X)) {} void set(const TX) { x = std::move(X); } T x; }; 
  • const Perfect forwarding (PF) тАФ will not compile
     class C { template<typename Z> C(const Z&& X) : x(std::forward<Z>(X)) {} template<typename Z> void set(const Z&& X) { x = std::forward<Z>(X); } T x; }; 



Working with smart pointers


  • Do not pass shared_ptr (or other countref alternatives) by value, if you do not need to count references (reduces performance due to atomic operations with counter) тАФ prefer passing objects by * or & as usual.
  • Do not pass shared_ptr (or other countref alternatives) by reference or const reference, if you do not need to count references тАФ prefer passing objects by * or & as usual.
  • If fabric has to return a polymorphic type (and thus cannot return by value), return unique_ptr, which can be converted to shared_ptr if needed (or return shared_ptr if you are sure that it will always be needed intead of unique_ptr)
  • If a function will need to decide if it wants to copy a shared_ptr or not тАФ you can pass a const shared_ptr& to it
  • Never dereference or call a method of non-local shared_ptr, because this puts object outside of shared_ptr control (instead, first make a local copy of shared_ptr). Example:




Links:


CppCon 2014: Herb Sutter "Back to the Basics! Essentials of Modern C++ Style"
PDF presentation
What is an 'aliased local shared_ptr' in this example?


Some of the used images were taken from the linked articles




Go to Part 1

Source: https://habr.com/ru/post/hi479358/


All Articles