#include <string>
#include <type_traits>
#include <iostream>
#include <utility>
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;
};
// if called with an rvalue (xvalue) as 2:nd arg, move or copy
TStruct get_or_default8(const TStruct& st, TStruct&& default_st) {
cout << "R";
if(st.a == 0)
return std::move(default_st); // rval, move ctor
// return std::forward<TStruct>(default_st); // alternative
else
return st; // lval, copy ctor
}
// lvalue as 2:nd argument, return the reference as-is
const TStruct& get_or_default8(const TStruct& st,
const TStruct& default_st) {
cout << "L";
if(st.a == 0) return default_st;
else return st;
}
void test_through3() {
TStruct lval = 1;
TStruct lval2 = 4;
TStruct lval3 = 0;
// First argument is returned
cout << endl << "First 2: ";
decltype(auto) s4 = get_or_default8(lval3, 2);
cout << endl << "First TS(3): ";
decltype(auto) s5 = get_or_default8(lval3, TStruct(3));
cout << endl << "First lval: ";
decltype(auto) s6 = get_or_default8(lval3, lval);
// Second argument is returned
cout << endl << "Second 2: ";
decltype(auto) s1 = get_or_default8(lval2, 2);
cout << endl << "Second TS(3): ";
decltype(auto) s2 = get_or_default8(lval2, TStruct(3));
cout << endl << "Second lval: ";
decltype(auto) s3 = get_or_default8(lval2, lval);
cout << endl;
cout << std::boolalpha;
cout << std::is_reference_v<decltype(s1)> << "\n";
cout << std::is_reference_v<decltype(s2)> << "\n";
cout << std::is_reference_v<decltype(s3)> << "\n";
cout << std::is_reference_v<decltype(s4)> << "\n";
cout << std::is_reference_v<decltype(s5)> << "\n";
cout << std::is_reference_v<decltype(s6)> << "\n";
}
int main() {
test_through3();
return 0;
}