C++ 11 variadic std :: function参数

Dan*_* K. 19 c++ templates variadic-templates c++11

一个名为teststd :: function <>的函数作为参数.

template<typename R, typename ...A>
void test(std::function<R(A...)> f)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我执行以下操作:

void foo(int n) { /* ... */ }

// ...

test(foo);
Run Code Online (Sandbox Code Playgroud)

编译器(gcc 4.6.1)说no matching function for call to test(void (&)(int)).

要使最后一行test(foo)编译并正常工作,我该如何修改该test()函数?在test()函数中,我需要f类型为std :: function <>.

我的意思是,是否有任何模板技巧让编译器确定函数的签名(foo在示例中),并将其std::function<void(int)>自动转换?

编辑

我想为lambdas(无论是声明的还是无状态的)做这项工作.

Joh*_*itb 12

看起来你想要使用重载

template<typename R, typename ...A>
void test(R f(A...))
{
    test(std::function<R(A...)>(f));
}
Run Code Online (Sandbox Code Playgroud)

这个简单的实现将接受大多数(如果不是所有)您将尝试传递的函数.异国情调的功能将被拒绝(如void(int...)).更多的工作将为您提供更多的通用性.

  • @Daniel你运气不好.或者让`test`成为一个接受任何东西的模板(`T`).`std :: function`无论如何都不会完全拒绝不兼容的函数对象,所以限制函数模板参数类型的目标对我来说似乎并不太有用. (4认同)

Pot*_*ter 7

std::function实现Callable接口,即它看起来像一个函数,但这并不意味着你应该要求可调用对象std::function.

template< typename F > // accept any type
void test(F const &f) {
    typedef std::result_of< F( args ) >::type R; // inspect with traits queries
}
Run Code Online (Sandbox Code Playgroud)

鸭子打字是模板元编程的最佳策略.接受模板参数时,不要特定,只需让客户端实现接口即可.

如果你真的需要一个std::function例如重新定位变量或类似的东西,并且你知道输入是原始函数指针,你可以分解原始函数指针类型并将其重建为一个std::function.

template< typename R, typename ... A >
void test( R (*f)( A ... ) ) {
    std::function< R( A ... ) > internal( f );
}
Run Code Online (Sandbox Code Playgroud)

现在用户无法传递,std::function因为已经封装在函数中.您可以将现有代码保留为另一个重载并仅委托给它,但要小心保持接口简单.

至于有状态的lambdas,我不知道如何处理这种情况.它们不会分解为函数指针,据我所知,参数类型无法查询或推断.std::function无论好坏,这些信息都是实例化所必需的.


use*_*249 6

这是一篇旧文章,我似乎找不到太多关于同一主题的内容,所以我想我应该继续写一个注释。

在GCC 4.8.2上编译,工作如下:

template<typename R, typename... A>
R test(const std::function<R(A...)>& func)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,您不能仅通过传入指针、lambda 等来调用它。但是,以下 2 个示例都可以使用它:

test(std::function<void(int, float, std::string)>(
        [](int i, float f, std::string s)
        {
            std::cout << i << " " << f << " " << s << std::endl;
        }));
Run Code Online (Sandbox Code Playgroud)

还:

void test2(int i, float f, std::string s)
{
    std::cout << i << " " << f << " " << s << std::endl;
}

// In a function somewhere:
test(std::function<void(int, float, std::string)>(&test2));
Run Code Online (Sandbox Code Playgroud)

这些的缺点应该非常明显:您必须为它们显式声明 std::function,这可能看起来有点难看。

尽管如此,我还是将其与一个扩展为调用传入函数的元组放在一起,并且它可以工作,只需要更多地明确说明您正在调用测试函数做什么。

包含元组的示例代码,如果您想使用它:http ://ideone.com/33mqZA

  • 只是为了好玩,我想出了一种使用 index_sequence 的方法(在 C++14 中添加,但很容易在 C++11 中自己实现)和 function_traits 样式结构来想出一些可以接受任何 lambda、函子、或函数,并使用它。[http://ideone.com/LNpj74](http://ideone.com/LNpj74) 显示了一个工作示例。但请注意,对于重载 2 个以上的 operator() 的函子,它需要一个额外的接口来指定要使用的类型。没有尝试使用多态函子,但我预计这也会引起问题...... (3认同)