// g++ -std=c++11 -Wall -Wextra -Wpedantic -o chain chain.cpp

#include <iostream>

#define DEL(X) \
    X = delete;
#define DEF(X, ...) \
    X \
    { \
        std::cout << this << " " << #X << std::endl; \
        __VA_ARGS__; \
    }
#define CHAIN(N) \
    DEF(S const &  N() const &,  return           *this;) \
    DEF(S       &  N()       &,  return           *this;) \
    DEF(S          N()       &&, return std::move(*this);)
    // DEF(S       && N()       &&, return std::move(*this);)

struct S
{
    DEF(S(),)
    DEF(~S(),)
    DEL(S(S const &))
    DEF(S(S       &&),)
    DEL(S & operator=(S const &))
    DEF(S & operator=(S       &&), return *this;)

    CHAIN(chain)
};

int main()
{
    auto s1 = S{}.chain();
    std::cout << &s1 << " " << "use" << std::endl;
    std::cout << std::endl;

    auto const & s2 = S{}.chain();
    std::cout << &s2 << " " << "use" << std::endl;
    std::cout << std::endl;

    auto s3 = S{};
    s3.chain();
    std::cout << std::endl;

    auto const s4 = S{};
    s4.chain();
    std::cout << std::endl;

    // 0x7ffef298ba3f S()
    // 0x7ffef298ba3f S chain() &&
    // 0x7ffef298ba3c S(S &&)
    // 0x7ffef298ba3f ~S()
    // 0x7ffef298ba3c use

    // 0x7ffef298ba3f S()
    // 0x7ffef298ba3f S chain() &&
    // 0x7ffef298ba3d S(S &&)
    // 0x7ffef298ba3f ~S()
    // 0x7ffef298ba3d use

    // 0x7ffef298ba3e S()
    // 0x7ffef298ba3e S & chain() &

    // 0x7ffef298ba3f S()
    // 0x7ffef298ba3f S const & chain() const &

    // 0x7ffef298ba3f ~S()
    // 0x7ffef298ba3e ~S()
    // 0x7ffef298ba3d ~S()
    // 0x7ffef298ba3c ~S()
}