c++ - 线性链式工厂和 move 语义

标签 c++ templates factory move-semantics expression-templates

我尝试制作链式工厂。

链将使用 move 语义来避免构造不必要的对象。

链接遵循 3 条规则:

  1. 除非一个工厂被标记为现在制造,否则两个工厂可以制造一个表达式:

    • A_maker ^ B_maker<...>变成 Exp<A_maker, B_maker>
  2. 除非工厂被标记为现在制造一个表达式,然后工厂制造一个新表达式:

    • Exp<...> ^ B_maker<...>变成 Exp<Exp<...>, B_maker<...>> .
  3. A_maker(..) ^ (B_maker(..).make()) 的语法会创建一个 B<A>对象。

我还没有实现制作 B<B<A>> 的逻辑,或将要求从后面的工厂传回前面的工厂。虽然对象的创建遵循工厂的顺序,但需求的传递与此顺序相反。

当前代码的问题在于它无法编译。

如何解决这个问题?

谢谢。

测试(也在 coliru )

#include <iostream>
#include <utility>

struct A {
    explicit A(int val) : val_(val) {}

    int val_{-1};
};

template<typename P=A>
struct B {
    B(P&& p, int val)
            : p_(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^(const Maker& m) {
        if (m.make_now_) {
            return m.syn(make());
        } else {
            return append(m);
        }
    }

    auto make() { return rest_.syn(top_.syn); }

private:
    template<typename New_maker>
    Exp<Top, Exp<Rest, New_maker>> append(
            New_maker&& new_maker) {
        return Exp(top_, Exp(rest_, 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, T>(std::move(*this),
                               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);
    }

private:
    B<P> syn(P&& p) { return B(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();
    return 0;
}

编译错误:

error: cannot bind rvalue reference of type 
    ‘B_maker<A>&&’ to lvalue of type ‘B_maker<A>’
         return Exp<A_maker, T>(std::move(*this), other_maker);
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

最佳答案

您必须使用 std::forward : https://godbolt.org/g/VfNk2G

你在函数中

template<typename T>
auto operator^(T&& other_maker) {
    return Exp<A_maker, T>(std::move(*this),
                           other_maker);
}

您正在尝试调用 Exp::Exp(Top&& top, Rest&& rest)并且编译器提示 rest (即 other_maker )属于 B_maker<A> 类型即使你的函数需要 B_maker<A>&& other_maker .这里的问题是,一旦你命名那个值,它突然又是一个左值并且不再是 B_maker<A>&& 类型。 . std::forward<T&&>通过再次使它成为右值引用来解决这个问题。

关于c++ - 线性链式工厂和 move 语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50355615/

相关文章:

amazon-web-services - 将字符串转换为 CommaDelimitedList Cloudformation 模板

c++ - GenericFactory 作为单例

c# - 如何实现委托(delegate)工厂?

c++ - openGL何时以及如何计算F_depth(深度值)

c++ - 在 C++ 中,使用 luabind,调用 lua 文件中定义的函数?

c++ - 在迷宫的 txt 文件中查找特定字符

c++ - GetProcAddress 与所有加载的库

c++ - 如何在 C++ 中为嵌套模板数字类型类编写构造函数?

具有默认参数的 C++ 模板

templates - Azure 数据工厂 V2 : auto-start trigger upon deployment?