C++ 高阶函数中的完美转发可调用对象

C++ 高阶函数中的完美转发可调用对象,c++,c++11,C++,C++11,我一直在写这样的高阶函数: template<typename F, typename... Args> void doStuff(F f, Args&&... args) { // ... f(std::forward<Args>(args)...); // ... } template<typename F, typename... Args> void doStuff(F&& f, Args&am

我一直在写这样的高阶函数:

template<typename F, typename... Args>
void doStuff(F f, Args&&... args)
{
    // ...
    f(std::forward<Args>(args)...);
    // ...
}
template<typename F, typename... Args>
void doStuff(F&& f, Args&&... args)
{
    // ...
    std::forward<F>(f)(std::forward<Args>(args)...);
    // ...
}
auto vec3 = std::move(foo)();
vec4 = foo();
然后我以前的
doStuff
实现将只调用
&
方法,因为参数总是左值

我认为解决这个问题的方法是实现如下
doStuff

template<typename F, typename... Args>
void doStuff(F f, Args&&... args)
{
    // ...
    f(std::forward<Args>(args)...);
    // ...
}
template<typename F, typename... Args>
void doStuff(F&& f, Args&&... args)
{
    // ...
    std::forward<F>(f)(std::forward<Args>(args)...);
    // ...
}
auto vec3 = std::move(foo)();
vec4 = foo();
模板
void doStuff(F&&F,Args&&…Args)
{
// ...

标准:正向(f)(std::forward。我想知道的是,这个实现有什么缺点,也就是说,我应该用它替换我所有的HOF实现吗?

std::forward
是一个有条件的r值强制转换,重点是像往常一样从垂死的对象中挖出内脏。
functor
和其他对象之间没有区别消极的一面与任何使用std::forward的方法都是一样的;如果你不准备去窃取那些胆量,你就不应该这样做

#include <iostream>
#include <vector>

struct Foo {
    std::vector<int> vec = {1,2,3};
    std::vector<int>& operator()(...) & {
        return vec;
    }
    std::vector<int> operator()(...) && {
        return std::move(vec);
        // Clearly, don't rely on 'vec' here...
    }
};

Foo getFoo(){
    return {};
}

int main() {
    auto foo = getFoo();
    auto vec1=foo();
    auto vec2=getFoo()();
}

出于同样的原因。

只要
f
之后不再被重用,它看起来就很好。
operator()
可能会有一些副作用,可能会修改
f
的内部成员(移动内部成员)(如果有的话)。不过我不确定,还没有考虑清楚。。问得好。@Arunmu if(1)该方法在ref限定符上重载,并且(2)调用者将函子作为右值传入,我们有足够的理由相信调用者打算调用
&&
版本。在这种情况下,在
doStuff
中完美地转发
f
可能是合理的。我想,
转发(f)没有任何问题
只要不在
doStuff
@Praetorian内再次使用
f
,为什么再次使用
f
会成为一个问题?
std::forward
只不过是一个条件转换,所以除非
&
方法引爆对象本身,否则重用
f
应该没问题。不?是的,但如果我通过实现ref限定的重载很麻烦,我可能只会在
&&
重载有机会通过窃取函子的内脏来提高效率时才这样做。在任何情况下,除非您还控制将传递给
doStuff
的每个函子,否则您必须假设它有一个
操作符()&&
修改函子,以便后续调用的行为可能不同。