#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) {
std::cout << "Dim(&&) = " << (uint64_t)this << " : " << (uint64_t)ptr << std::endl;
}
~Dim() {
std::cout << "~Dim() = " << (uint64_t)this << 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) {
std::cout << "Group(&&) = " << (uint64_t)this << " : " << (uint64_t)ptr << std::endl;
}
};
Dim Cross::dim() {
Dim d(this);
return d;
}
Group Dim::group() {
std::cout << "Dim::group = " << (uint64_t)this << std::endl;
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<decltype(d)>(std::move(d));
return Cons<decltype(op)>(std::move(op));
}
template<typename G>
decltype(auto) make_consumer2(G && g) { // <---------если здесь передавать аргумент по значению, то проблема исчезает.
auto gop = Op<decltype(g)>(std::move(g));
return Cons<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; // <------------ ERROR: должно напечатать 10, а печатает мусор
return 0;
}