#include <iostream>
struct Dim;
struct Group;
struct Cross {
int i;
Cross(int l):i(l) { std::cout << "Cross() = " << (uint64_t)this << std::endl;}
Dim dim();
};
struct Dim {
Cross * ptr;
explicit Dim(Cross * c):ptr(c) {
std::cout << "Dim(Cross*) = " << (uint64_t)this << " : " << (uint64_t)ptr << std::endl;
}
Dim(Dim && d):ptr(d.ptr) {
d.ptr = nullptr;
std::cout << "Dim(&&) = " << (uint64_t)this << " : " << (uint64_t)ptr << std::endl;
}
Group group();
};
struct Group {
Dim * ptr;
explicit Group(Dim * c):ptr(c) {
std::cout << "Group(Dim*) = " << (uint64_t)this << " : " << (uint64_t)ptr << std::endl;
}
Group(Group && d):ptr(d.ptr) {
d.ptr = nullptr;
std::cout << "Group(&&) = " << (uint64_t)this << " : " << (uint64_t)ptr << std::endl;
}
};
Dim Cross::dim() {
Dim d(this);
return d;
}
Group Dim::group() {
Group g(this);
return g;
}
template<typename D>
struct Op {
D g;
Op(Op && o):g(std::move(o.g)) {
std::cout << "Op(&&) = " << (uint64_t)this << " : " << (uint64_t)g.ptr << std::endl;
}
Op(D && gg):g(std::move(gg)) {
std::cout << "Op(D&&) = " << (uint64_t)this << " : " << (uint64_t)g.ptr << std::endl;
}
};
template<typename D>
struct Cons {
D op;
Cons(Cons && c):op(std::move(c.op)) {
std::cout << "Cons(&&) = " << (uint64_t)this << " : " << (uint64_t)op.g.ptr << std::endl;
}
explicit Cons(D && gg):op(std::move(gg)) {
std::cout << "Cons(Op&&) = " << (uint64_t)this << " : " << (uint64_t)op.g.ptr << std::endl;
}
};
template<typename D>
decltype(auto) make_consumer1(D &&d) {
auto op = Op<std::decay_t<D>>(std::move(d));
return Cons<std::decay_t<decltype(op)>>(std::move(op));
}
template<typename G>
decltype(auto) make_consumer2(G && g) { // <---------если здесь передавать аргумент по значению, то проблема исчезает.
auto gop = Op<std::decay_t<G>>(std::move(g));
return Cons<std::decay_t<decltype(gop)>>(std::move(gop));
}
int main() {
Cross c(10);
auto cons1 = make_consumer1(c.dim());
std::cout << "cons1 "<< cons1.op.g.ptr->i << std::endl;
auto cons2 = make_consumer2(cons1.op.g.group());
std::cout << cons2.op.g.ptr->ptr->i << std::endl;
return 0;
}