如果我理解正确,编写一个接受任何可调用作为参数的函数的标准方法是:
template<typename Fn> void myFunction(Fn&& f) { ... }
我想做类似的事情,除了我希望能够使Fn
符合某个签名,我需要知道其参数的类型。例如,像:
template<typename T> void myFunction(std::function<void (T)>&& f) { ... }
问题是这不能接受packaged_task
或lambdas捕获只移动类型的std::promise
。
更新:添加了一个示例用例
考虑简化的网络请求功能:
template<typename T> void get(const Url& url,
const UrlQuery& params,
std::function<void (T)>&& callback) {
auto response = doGet(url, query);
callback(fromJson<T>(response));
}
这在大多数情况下运行得相当好,但是当我尝试传递它时,捕获std::promise
的lambda失败了。我可以使用一些变通方法来完成这项工作,但我想知道是否有更优雅的方式。更接近这个伪代码:
template<typename Fn<T>>
void get(const Url& url,
const UrlQuery& params,
Fn<T>&& callback) {
auto response = doGet(url, query);
callback(fromJson<T>(response));
}
显然这不会编译,但它会显示我想要的内容。
要在T
正文中隐藏get
参数,同时保留Fn&&
样式参数(例如,不指定std::function
或std::packaged_task
作为callback
的类型,并且在调用get
时也不需要跳过任何箍。
答案 0 :(得分:0)
以下,解决了非可复制的lambda部分,适用于MinGW g ++ 7.2和Visual C ++ 2017:
#include <functional> // std::function
#include <memory> // std::shared_ptr
#include <utility> // std::move
template< class Type >
void foo( std::function<void (Type)>&& f )
{
f( 42 );
}
struct No_copy
{
No_copy( No_copy const& ) = delete;
auto operator=( No_copy const& ) -> No_copy& = delete;
No_copy() {}
No_copy( No_copy&& ) {}
auto operator=( No_copy&& ) -> No_copy& { return *this; }
};
template< class Type >
class Copyable
{
std::shared_ptr<Type> pf_;
public:
template< class... Args >
auto operator()( Args&&... args )
{ return (*pf_)( std::forward<Args>( args )... ); }
Copyable( Type&& o )
: pf_{ std::make_shared<Type>( std::move( o ) ) }
{}
};
// Necessary for Visual C++ 2017:
template< class Type >
auto copyable( Type&& o ) { return Copyable<Type>{ std::move( o ) }; }
#include <iostream>
using namespace std;
auto main()
-> int
{
No_copy o;
#ifdef DETAILED
auto lambda = [oh{move(o)}]( int x ){ cout << x << " " << &oh << endl; };
auto const c = copyable( move( lambda ) );
foo<int>( c );
#else
foo<int>( copyable( [oh{move(o)}]( int x ){ cout << x << " " << &oh << endl; } ) );
#endif
}
我没有尝试过你提到的特定类型。
此外,如果您需要,此代码不会解决推断参数类型的问题(如果需要,您必须添加此类推论)。
而且,嗯,存在可能的引用返回类型的问题,这里也没有解决。
:)