基于移动语义的线性链式工厂编译错误修复求助
首先,我们来拆解你遇到的编译错误:
error: cannot bind rvalue reference of type 'B_maker&&'to lvalue of type 'B_maker'return Exp<A_maker, T>(std::move(*this), other_maker); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这个错误的核心是完美转发失效:A_maker::operator^接收的other_maker虽然是右值引用模板参数,但参数本身在函数内是左值,直接传给Exp构造函数(期望右值引用)时无法绑定。除此之外,你的代码还有多处逻辑问题,比如Exp::make()调用成员的方式错误、append方法的嵌套构造逻辑错误、make_now_的访问权限问题等,下面是完整的修复方案:
第一步:修复编译错误(完美转发参数)
修改A_maker::operator^,使用std::forward保留参数的右值属性,同时用std::remove_reference_t处理模板类型,避免引用类型被存储到Exp中:
template<typename T> auto operator^(T&& other_maker) { return Exp<A_maker, std::remove_reference_t<T>>( std::move(*this), std::forward<T>(other_maker) // 完美转发,保留右值属性 ); }
第二步:修复Exp::make()的逻辑错误
原代码中rest_.syn(top_.syn)是错误的——syn是成员函数而非成员变量,我们需要把top_.make()生成的对象传递给rest_.syn:
auto make() { return rest_.syn(top_.make()); }
第三步:修复Exp::append()的嵌套构造逻辑
原append方法的Exp构造方式错误,需要正确嵌套表达式对象,同时继续使用完美转发传递新工厂:
template<typename New_maker> auto append(New_maker&& new_maker) { return Exp<Exp<Top, Rest>, std::remove_reference_t<New_maker>>( std::move(*this), std::forward<New_maker>(new_maker) ); }
同时调整Exp::operator^的判断逻辑,改用公共接口访问make_now_(避免私有成员访问问题):
template<typename Maker> auto operator^(Maker&& m) { if (m.is_make_now()) { return m.syn(make()); } else { return append(std::forward<Maker>(m)); } }
第四步:修复B_maker的访问权限与make()方法
为B_maker添加公共接口is_make_now()供Exp访问,同时限制make()仅能被右值调用(避免悬垂引用):
template<typename P=A> class B_maker { using self_type = B_maker<P>; public: explicit B_maker(int val) : val_(val) {} // 仅允许右值对象调用make() self_type make() && { make_now_ = true; return std::move(*this); } // 公共接口,让Exp判断是否立即创建 bool is_make_now() const { return make_now_; } private: B<P> syn(P&& p) { return B(std::move(p), val_); } bool make_now_{false}; int val_; template<typename T, typename R> friend class Exp; };
第五步:支持B<B<A>>的嵌套生成
修复后的代码已经支持嵌套链式调用,比如A_maker(0) ^ B_maker<>(1) ^ B_maker<B<A>>(2).make()会生成B<B<A>>对象,核心是Exp::make()的递归调用逻辑会逐层传递前序工厂的生成结果。
完整修复后的代码
#include <iostream> #include <utility> #include <type_traits> struct A { explicit A(int val) : val_(val) {} int val_{-1}; }; template<typename P=A> struct B { B(P&& p, int val) : p_(std::move(p)), val_(val) {} P p_; int val_{-1}; }; template<typename Top, typename Rest> class Exp { public: Exp(Top&& top, Rest&& rest) : top_(std::move(top)), rest_(std::move(rest)) {} template<typename Maker> auto operator^(Maker&& m) { if (m.is_make_now()) { return m.syn(make()); } else { return append(std::forward<Maker>(m)); } } auto make() { return rest_.syn(top_.make()); } private: template<typename New_maker> auto append(New_maker&& new_maker) { return Exp<Exp<Top, Rest>, std::remove_reference_t<New_maker>>( std::move(*this), std::forward<New_maker>(new_maker) ); } Top top_; Rest rest_; }; class A_maker { public: explicit A_maker(int val) : val_(val) {} auto make() { return syn(); } template<typename T> auto operator^(T&& other_maker) { return Exp<A_maker, std::remove_reference_t<T>>( std::move(*this), std::forward<T>(other_maker) ); } private: A syn() { return A(val_); } int val_; template<typename T, typename R> friend class Exp; }; template<typename P=A> class B_maker { using self_type = B_maker<P>; public: explicit B_maker(int val) : val_(val) {} self_type make() && { make_now_ = true; return std::move(*this); } bool is_make_now() const { return make_now_; } private: B<P> syn(P&& p) { return B(std::move(p), val_); } bool make_now_{false}; int val_; template<typename T, typename R> friend class Exp; }; int main() { // 基础场景测试 B bba(B(A(0), 1), 2); auto x = A_maker(0) ^ B_maker(1).make(); std::cout << x.p_.val_ << ", " << x.val_ << std::endl; // 输出:0, 1 // 嵌套B<B<A>>场景测试 auto y = A_maker(0) ^ B_maker<>(1) ^ B_maker<B<A>>(2).make(); std::cout << y.p_.p_.val_ << ", " << y.p_.val_ << ", " << y.val_ << std::endl; // 输出:0, 1, 2 return 0; }
关于反向传递需求的实现思路
如果要实现后续工厂的需求反向传递给前置工厂,你可以:
- 为每个工厂添加类型特征(比如
required_arg_type),标记该工厂需要的前置参数类型 - 在
Exp的make()过程中,递归地让前置工厂根据后续工厂的类型特征调整创建逻辑 - 例如
B_maker<B<A>>需要B<A>作为参数,前置的B_maker需要动态生成B<A>而非默认的B
内容的提问来源于stack exchange,提问作者R zu

