完美转发仿函数

时间:2016-02-11 20:30:23

标签: c++ templates functor perfect-forwarding

我想知道使用完美转发仿函数的正确方法是什么?这是两个代码段。哪一个是最好的,如果不是,哪个是最好的形式?

template<typename T, typename... Args>
void callMe(T&& func, Args&&... args) {
    func(std::forward<Args>(args)...);
}

或者

template<typename T, typename... Args>
void callMe(T&& func, Args&&... args) {
    std::forward<T>(func)(std::forward<Args>(args)...);
}

编辑:

它会影响重载分辨率吗?如果func的{​​{1}}具有operator()&&的参考限定符,我应该执行后一版本吗?我应该关注我调用的重载吗?

谢谢!

2 个答案:

答案 0 :(得分:5)

如果您要对象(可能是右值)传递给其他某个功能,并且您不确定它是否属于右值或左值。在这种情况下,您只需使用 func,因此转发它不会有任何好处或伤害。

请记住,std::forward是条件std::move,它只是对r值引用的强制转换。

此外,如果可能会为您转发的内容调用复制或移动构造函数,那么它才真正有用。在许多情况下,const T&会做得很好。

修改

正如莓果指出的那样,如果func具有参考资格operator(),那么确实无关紧要。我从未见过或使用过合格的方法(据我所知。这非常罕见。)Barry的回答更多。

它也会读到这个:What is "rvalue reference for *this"?

struct C {
    void operator()() && { std::cout << "rval\n"; }
    void operator()() const & { std::cout << "lval\n"; }
};

callMe(C{});

答案 1 :(得分:5)

由于存在ref-qualified operator(),因此第一个版本可能做错了。考虑:

struct C {
    void operator()() && { std::cout << "rval\n"; }
    void operator()() const & { std::cout << "lval\n"; }
};

callMe(C{});

我给你一个右值 - 并期望看到"rval" - 但在第一个版本中,你总是像左值一样对待函数对象 - 所以我真的看到了{{ 1}}。

所以正确的解决方案将是第二个 - "lval" s forward也是如此。

在实践中,我不知道参与合格的成员函数实际发生的频率,所以前者很可能。