避免使用`operator <<`推迟"子"对象构造

Vit*_*meo 4 c++ constructor operator-overloading variadic-templates c++14

假设我有一个容器对象来存储std::vector多态子.

struct Child
{
    Child(Parent& mParent) { /* ... */ }
    virtual ~Child() { }
};

class Parent
{
    private:
        std::vector<std::unique_ptr<Child>> children;

        template<typename T, typename... TArgs> 
        auto& mkChild(TArgs&&... mArgs)
        {
            // `static_assert` that `T` is derived from `Child`...
            children.emplace_back(std::make_unique<T>(std::forward<TArgs>(mArgs)...));
            return *children.back();
        }

    public:
        template<typename T, typename... TArgs> 
        auto& add(TArgs&&... mArgs)
        {
            mkChild<T>(std::forward<TArgs>(mArgs)...));
            return *this;
        }
};
Run Code Online (Sandbox Code Playgroud)

现在我可以使用这样的Parent类:

int main()
{
    Parent p;
    p.add<Child1>(some_args1).add<Child2>(some_args2);
}
Run Code Online (Sandbox Code Playgroud)

虽然这种语法实现了我想做的事情(将子项添加到单个父项中),但我觉得很难阅读,特别是在我的实际用例中.

我真的很想用operator<<.但我无法想出一种方法来构建孩子.

// Desired syntax
int main()
{
    Parent p;
    p << mk<Child1>(some_args1) << mk<Child2>(some_args2);
}
Run Code Online (Sandbox Code Playgroud)

请注意我从未在mk函数中指定父级.

我不想说mk<Child1>(p, some_args1).编译器应该p从链接中找出答案operator<<.

有什么方法可以实现这个mk函数生成等于通过.add<T>(...)链接生成的代码?

我设法实现这一点的唯一方法是使用一个中间人结构,该结构包含子类的构造可变参数.

template<typename T, typename... TArgs> struct DeferCtor
{
    std::tuple<TArgs...> ctorArgs;
};
Run Code Online (Sandbox Code Playgroud)

然后operator<<(DeferCtor<T, TArgs...>&)将处理对象的内部构造Parent.

有没有办法避免这一步,同时仍然有所需的语法?(不在mk函数中传递父实例.)

Chr*_*odd 6

您实际上并没有在现有代码中创建对象 - 您使用a在堆上创建子对象unique_ptr,然后移动unique_ptr到父对象中.operator<<如果您将其定义为采用以下方法,则可以对您执行相同的操作unique_ptr:

Parent &Parent::operator<<(std::unique_ptr<Child> ch) {
    children.emplace_back(std::move(ch)); }
Run Code Online (Sandbox Code Playgroud)

现在假设你的mk全局函数基本上只是一个别名make_unique:

template<typename T, typename... TArgs> 
std::unique_ptr<T> mk(TArgs&&... mArgs) {
    return std::make_unique<T>(std::forward<TArgs>(mArgs)...)); }
Run Code Online (Sandbox Code Playgroud)

你应该能够使用你想要的语法.