#include <utility>
#include <iostream>

struct trace
{
    trace() { std::cout << "default ctor\n"; }
    trace( trace const& ) { std::cout << "copy ctor\n"; }
    trace& operator=( trace const& ) { std::cout << "copy assign\n"; return *this; }
    ~trace()  { std::cout << "dtor\n"; }
    friend void swap( trace& x, trace& y ) { std::cout << "swap\n"; }
};


template <class T>
struct assignment
{
    assignment(T& lhs) : lhs(lhs) {}
    
    template <class U>
    T& operator=(U& lvalue)
    {
        return lhs = lvalue;
    }

    struct ref
    {
        ref(T const& mutable_rvalue)
          : m(const_cast<T&>(mutable_rvalue))
        {
        }

        T& m;
    };
        
    T& operator=(ref x)
    {
        swap(lhs, x.m);
        return lhs;
    }
    
    T& lhs;
};

template <class T>
assignment<T> assign(T& x) { return assignment<T>(x); }

trace const const_rvalue() { return trace(); }

int main()
{
    trace x;
    trace dst;
      
    std::cout << "=== rvalue ===\n";
    assign(dst) = trace();
      
    std::cout << "=== const rvalue ===\n";
    assign(dst) = const_rvalue();
      
    std::cout << "=== lvalue ===\n";
    assign(dst) = x;
      
    std::cout << "=== const lvalue ===\n";
    trace const& y = x;
    assign(dst) = y;
    std::cout << "=== done ===\n";
}


