C++存储转发通用引用的函数

C++ store functions that forward universal references

本文关键字:函数 引用 存储转发 C++      更新时间:2023-10-16

是否可以存储与以下函数具有类似行为的函数:

void target(int foo, size_t bar) {}
void target(std::string foo, int bar) {} 
template<T...>
void forwarding_func(T&&... args)
{
    target(std::forward<T>(args)...);
}
auto forwarding_callable = ?

如何为与forwarding_func具有相同行为的 T 类型构建可调用对象。我必须存储它以供以后使用,所以我确实需要一个 std::function 对象?甚至可以在函数对象中存储这样的 lambda 吗?

auto f = [](auto&& x){
      myfunction(std::forward<decltype(x)>(x));
} 

你需要一个函数对象,即一个带有 operator() 的函数对象。此运算符应为模板,并具有与 forwarding_func 相同(或相似)的签名。您可以通过多种方式构建一个。

最直接的方法是使用 C++17 通用 lambda。如果你不能使用它,你可以定义你自己的:

struct forwarder {
    template <typename ... Args>
       void operator()(Args&& ... args) { ... etc }
};
有一种

完全不同的方法来创建这样的转发器。有人建议向标准库添加overload函数。你会像这样使用它:

auto callable = std::overload (
   (void (*)(int, size_t))(target),
   (void (*)(std::string, int))(target)
);

编译器没有实现 std::overload,因为它还不是任何标准的一部分,但你可以轻松地自己实现它,或者在网上找到一个实现(例如,请参阅这个问题)。

通用引用和std::forward仅在函数模板中有意义,因为在这种情况下,您不知道您的参数是否是左值引用。如果是,您希望按原样传递它,如果不是,您希望将其move到要转发到的函数中。这正是std::foward所做的。这是对右值引用和完美转发的一个非常好的介绍。由于非模板函数指定它们是按值还是按(左值)引用获取参数,因此您可以相应地移动或不移动它们,并且不需要std::foward

由于函数模板本身实际上不是函数,因此您无法将它们存储在 lambda 中。但是,您可以使用模板化operator()创建函子:

struct Forwarding_Functor
{
    template<class... T>
    void operator()(T&&... args)
    {
        target(std::forward<T>(args)...);
    }
};