(ditto here too! and at this point it is ok to browse away from this page), and finally, pass-by universal reference (more formally, perfect forwarding ... T&& ... I think universal references deserve their own spot in this overcrowded VIP lounge because they are really special and they don't have 4 variations). So that makes it 21.

void attempt_move(std::initializer_list<std::string> list) { // Copy lvalues and move rvalues in the list } int main(int argc, char *argv[]) { std::string s(argv[0]); if(argc >= 4) attempt_move({ s, argv[1], argv[2], argv[3] }); { // The underlying array initialization is roughly equivalent to std::string __list[4] = { s, std::string{argv[1]}, std::string{argv[2]}, std::string{argv[3]} }; attempt_move(std::initializer_list<std::string>(__list, __list + 4)); // __list[0] is an lvalue and others are rvalues } }

template <typename T> class in; template <typename T> struct is_in { static const bool value = false; }; template <typename T> struct is_in<in<T>> { static const bool value = true; }; template <typename T> struct is_in<const in<T>> { static const bool value = true; }; template <typename T> class in { public: in (const T& l): v_ (l), rv_ (false) {} in (T&& r): v_ (r), rv_ (true) {} // Support for implicit conversion via perfect forwarding. // struct storage { storage (): created (false) {} ~storage () { if (created) reinterpret_cast<T*> (&data)->~T (); } bool created; typename std::aligned_storage<sizeof(T), alignof(T)>::type data; }; template <typename T1, typename std::enable_if< std::is_convertible<T1, T>::value && !is_in<typename std::remove_reference<T1>::type>::value, int>::type = 0> in (T1&& x, storage&& s = storage ()) : v_ (*new (&s.data) T (std::forward<T1>(x))), rv_ (true) {s.created = true;} in (T& l): v_ (l), rv_ (false) {} // For T1&& becoming T1&. // Accessors. // bool lvalue () const {return !rv_;} bool rvalue () const {return rv_;} operator const T& () const {return v_;} const T& get () const {return v_;} T&& rget () const {return std::move (const_cast<T&> (v_));} // Return a copy if lvalue. // T move () const { if (rv_) return rget (); else return v_; } private: const T& v_; bool rv_; };

std::vector<std::string> attempt_move(std::initializer_list<in<std::string>> list) { std::vector<std::string> result; result.reserve(list.size()); for(const in<std::string> & s : list) { if(s.rvalue()) { // rvalue string. Just move. // in<T>.rget() returns T&& result.push_back(s.rget()); } else { // lvalue string. Make a copy // in<T>.get() returns const T &. result.emplace_back(s.get()); } } return result; } int main(int argc, char *argv[]) { std::string s(argv[0]); if(argc >= 4) attempt_move({ s, argv[1], argv[2], argv[3] }); }

calling a function

struct matrix { matrix () {} matrix (matrix const&) {cout << "copy-ctor, ";} matrix (matrix&&) {cout << "move-ctor, ";} matrix & operator = (matrix const &) { cout << "copy-assign, "; return *this; } matrix & operator = (matrix &&) { cout << "move-assign, "; return *this; } matrix& operator+= (const matrix &m) { return *this; } std::vector<int> data; }; #ifdef IN inline matrix operator+ (in<matrix> x, in<matrix> y) { return std::move ( x.rvalue () ? x.rget () += y : y.rvalue () ? y.rget () += x : matrix (x) += y); } #else inline matrix operator+ (matrix result, matrix const& y) { result += y; return result; } #endif int main() { matrix s1; matrix s2; matrix m1 (matrix() + s1); cout << endl;// (1) matrix m2 (matrix() + matrix()); cout << endl;// (2) matrix m3 (s1 + s2); cout << endl;// (3) matrix m4 (s1 + matrix()); cout << endl;// (4) }