嵌套绑定表达式

use*_*543 13 c++ bind c++11

这是我上一个问题的后续问题.

#include <functional>

int foo(void) {return 2;}

class bar {
public:
    int operator() (void) {return 3;};
    int something(int a) {return a;};
};

template <class C> auto func(C&& c) -> decltype(c()) { return c(); }

template <class C> int doit(C&& c) { return c();}

template <class C> void func_wrapper(C&& c) { func( std::bind(doit<C>, std::forward<C>(c)) ); }

int main(int argc, char* argv[])
{
    // call with a function pointer
    func(foo);
    func_wrapper(foo);  // error

    // call with a member function
    bar b;
    func(b);
    func_wrapper(b);

    // call with a bind expression
    func(std::bind(&bar::something, b, 42));
    func_wrapper(std::bind(&bar::something, b, 42)); // error

    // call with a lambda expression
    func( [](void)->int {return 42;} );
    func_wrapper( [](void)->int {return 42;} );

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我在C++头文件中遇到了编译错误:

functional:1137: error: invalid initialization of reference of type ‘int (&)()’ from expression of type ‘int (*)()’
functional:1137: error: conversion from ‘int’ to non-scalar type ‘std::_Bind<std::_Mem_fn<int (bar::*)(int)>(bar, int)>’ requested

func_wrapper(foo)应该执行func(doit(foo)).在实际代码中,它打包了要执行的线程的函数.func将由另一个线程执行该函数,它们介于两者之间以检查未处理的异常并进行清理.但是func_wrapper中的额外绑定搞砸了......

Sté*_*hen 2

现在第二次看这个,我想我对你看到的第一个错误有一个合理的解释。

\n\n

在这种情况下,查看完整的错误和导致该错误的模板实例化会更有帮助。例如,我的编译器(GCC 4.4)打印的错误以以下几行结尾:

\n\n
test.cpp:12:   instantiated from \xe2\x80\x98decltype (c()) func(C&&) [with C = std::_Bind<int (*(int (*)()))(int (&)())>]\xe2\x80\x99\ntest.cpp:16:   instantiated from \xe2\x80\x98void func_wrapper(C&&) [with C = int (&)()]\xe2\x80\x99\ntest.cpp:22:   instantiated from here\n/usr/include/c++/4.4/tr1_impl/functional:1137: error: invalid initialization of reference of type \xe2\x80\x98int (&)()\xe2\x80\x99 from expression of type \xe2\x80\x98int (*)()\xe2\x80\x99\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在从下往上看,实际的错误消息似乎是正确的;编译器推导的类型兼容。

\n\n

第一个模板实例化 at清楚地显示了编译器从 中func_wrapper的实际参数推导出来的类型。我个人期望 this 是一个函数指针,但实际上它是一个函数引用foofunc_wrapper(foo)

\n\n

第二个模板实例化几乎不可读。但是稍微搞了一下std::bind,我了解到 GCC 为绑定函子打印的文本表示的格式大致是:

\n\n
std::_Bind<RETURN-TYPE (*(BOUND-VALUE-TYPES))(TARGET-PARAMETER-TYPES)>\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以把它拆开:

\n\n
std::_Bind<int (*(int (*)()))(int (&)())>\n// Return type: int\n// Bound value types: int (*)()\n// Target parameter types: int (&)()\n
Run Code Online (Sandbox Code Playgroud)\n\n

这就是不兼容类型开始的地方。显然,即使cinfunc_wrapper是函数引用,但一旦传递给,它就会变成函数指针std::bind,导致类型不兼容。对于它的价值来说,std::forward在这种情况下根本不重要。

\n\n

我在这里的推理是,std::bind似乎只关心值,而不关心引用。在 C/C++ 中,不存在函数值这样的东西;只有引用和指针。因此,当函数引用被取消引用时,编译器只能给你一个有意义的函数指针。

\n\n

您对此唯一的控制权是您的模板参数。您必须告诉编译器您从一开始就正在处理函数指针才能使其工作。无论如何,这可能就是你的想法。为此,请明确指定模板参数所需的类型C

\n\n
func_wrapper<int (*)()>(foo);\n
Run Code Online (Sandbox Code Playgroud)\n\n

或者更简短的解决方案,显式获取函数的地址:

\n\n
func_wrapper(&foo); // with C = int (*)()\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我发现第二个错误,我会回复你。:)

\n