如何在非泛型类型上实现完美转发? [英] How to implement perfect forwarding on a non-generic type?

查看:127
本文介绍了如何在非泛型类型上实现完美转发?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有以下代码:

class Element;
typedef shared_ptr<Element> ElementPtr;

class Element
{
public:
    void add_child(const ElementPtr& elem);

private:
    vector<ElementPtr> children;
}

inline void Element::add_child(const ElementPtr& elem)
{
    children.push_back(elem);
};

我想更新add_child以使用完美的转发.我尝试更改函数定义(和声明),因此请使用以下逻辑:

And I want to update add_child to use perfect forwarding. I tried changing the function definition (and declaration) so use the following logic:

void Element::add_child(ElementPtr&& elem)
{
    children.push_back(forward<ElementPtr>(elem));
}

但是,对于参数elem为左值的任何调用,这都会崩溃.所以我想我会尝试使用模板并提出以下建议:

But this crashes for any call in which the argument elem is an lvalue. So I thought I'd try it with templates and came up with the following:

template <ElementPtr elem>
void Element::add_child(ElementPtr&& elem)
{
    children.push_back(forward<ElementPtr>(elem));
}

...但这无法编译.所以我将其更改为:

...But this does not compile. So I changed it to this:

template <class T>
void Element::add_child(T&& elem)
{
    children.push_back(forward<T>(elem));
}

...虽然可以编译和工作,但看起来丑陋且不适当; add_child只会接受类型为ElementPtr的参数,所以它的函数声明不应该反映这一点吗?

...Which compiles and works, but seems ugly and improper; add_child will only ever accept arguments of type ElementPtr, so shouldn't its function declaration reflect this?

在语法上证明该函数仅接受一种变量时,是否有任何方法可以实现对函数的完美转发?我基本上想要一个可以自动区分特定参数类型的左值和右值版本的函数.

Is there any way to implement perfect forwarding for a function while syntactically demonstrating that it only accepts one kind of variable? I basically want a function that will automatically distinguish between lvalue and rvalue versions of a specific parameter type.

推荐答案

您的选项是

  1. 使用两个重载(也称为"vector::push_back的作用"):

void add_child(const ElementPtr& elem) { children.push_back(elem); }
void add_child(ElementPtr&& elem) { children.push_back(std::move(elem)); }

  • 使用单个重载,该重载按值接受参数:

  • Use a single overload that takes its argument by value:

    void add_child(ElementPtr elem) { children.push_back(std::move(elem)); }
    

  • SFINAE.

  • SFINAE.

    template <class T,
              class = std::enable_if_t<std::is_same<ElementPtr, std::decay_t<T>>{}>>
    void Element::add_child(T&& elem)
    {
        children.push_back(forward<T>(elem));
    }
    

  • 选项2最多需要多移动一次,但移动shared_ptr很便宜,因为您无需触摸参考计数.选项1是有效的,但容易组合爆炸.选项3也是有效的,但更难以阅读和维护.

    Option 2 costs up to one additional move, but moving shared_ptrs is cheap since you don't need to touch the reference count. Option 1 is efficient, but subject to combinatorial explosion. Option 3 is also efficient, but is more difficult to read and maintain.

    这篇关于如何在非泛型类型上实现完美转发?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆