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函数中传递父实例.)
您实际上并没有在现有代码中创建对象 - 您使用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)
你应该能够使用你想要的语法.