C ++函数接受给定模板签名的任何可调用

时间:2018-02-07 01:44:56

标签: c++ c++14

如果我理解正确,编写一个接受任何可调用作为参数的函数的标准方法是:

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::functionstd::packaged_task作为callback的类型,并且在调用get时也不需要跳过任何箍。

1 个答案:

答案 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
}

我没有尝试过你提到的特定类型。

此外,如果您需要,此代码不会解决推断参数类型的问题(如果需要,您必须添加此类推论)。

而且,嗯,存在可能的引用返回类型的问题,这里也没有解决。

:)