在高阶函数中完美转发可调用对象

Ziz*_*Tai 11 c++ c++11

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

template<typename F, typename... Args>
void doStuff(F f, Args&&... args)
{
    // ...
    f(std::forward<Args>(args)...);
    // ...
}
Run Code Online (Sandbox Code Playgroud)

或者可以替换F fF&& f.

但在我了解了ref-qualifiers(哎哟)之后,情况变得复杂了.想象一个仿函数类:

struct Foo {
    void operator()(...) &;
    void operator()(...) &&;
};
Run Code Online (Sandbox Code Playgroud)

然后我之前的实现doStuff将只调用该&方法,因为参数总是左值.

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

template<typename F, typename... Args>
void doStuff(F&& f, Args&&... args)
{
    // ...
    std::forward<F>(f)(std::forward<Args>(args)...);
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这也是如何std::result_of可能实现的.我想知道的是,这个实现有什么缺点,即我应该用它替换所有的HOF实现吗?

Joh*_*erg 0

std::forward是一个有条件的 r 值转换,重点是像往常一样从垂死的物体中窃取内脏。functors在这方面与其他对象没有区别。其缺点与任何使用 ; 的情况相同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()();
}
Run Code Online (Sandbox Code Playgroud)

显然,不要做这样的事情:

auto vec3 = std::move(foo)();
vec4 = foo();
Run Code Online (Sandbox Code Playgroud)

出于同样的原因。