2017-10-07 41 views
1

是否有可能存储有类似行为以下功能的函数:C++店函数转发普遍引用

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 = ? 

如何将一个建立类型T上的可调用对象具有相同的行为forwarding_func。我必须存储它以备后用,所以我确实需要一个std :: function对象?是否有可能在函数对象中存储像这样的lambdas?

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

是的,可以使用lambda表达式。如果你想存储它们,你可以使用'std :: function'或者一个以传递的lambda对象的类型为模板的类。 –

+1

在std :: function对象中可以存储这样的东西,但不存储*。 –

+0

请注意,您的示例lambda会(如果它工作)不采取通用的引用,而是一个右值引用,即。它只会接受rvalues作为论证。我知道你明确地要求如何做到这一点,但在我看来,这仍然存在一些混淆。您可能想阅读Scott Meyer的文章(https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers)关于通用和右值引用之间的区别。 – Knoep

回答

2

你需要一个函数对象,就是一个与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 ::超载,因为它不是任何标准的一部分,但你可以很容易地实现它自己或在网络上找到的实现(例如参见this question)。

0

通用引用和std::forward才有意义在功能模板,在这种情况下,你不知道你的说法是否是左值参考与否。如果是的话,你想按原样传递它,如果不是的话,你想把它转换成你要转发的函数。这正是std::foward所做的。 Here是对右值引用和完美转发的非常好的介绍。 由于非模板函数指定它们是通过值还是通过(左值)引用来引用它们的参数,因此您可以相应地移动或不移动它们,并且不需要std::foward

由于函数模板本身并不是实际的函数,所以不能将它们存储在lambda表达式中。但是,您可以创建一个仿函数与模板operator()

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