C++绑定返回类型模板参数



我有以下一段代码:

#include <functional>
template <typename T>
class TD;   // For displaying type
void f(int, int, int) {  }
int main() {
    auto g = std::bind(f, std::placeholders::_1, 2, 2);
    TD<decltype(g)> td1;
    return 0;
}

在此代码中,TD是一个模板技巧,用于显示通过 decltype 传递的模板参数。

编译器的输出如下(以C++14模式编译(:

prog.cpp: In function 'int main()':
prog.cpp:10:18: error: aggregate 'TD<std::_Bind<void (*(std::_Placeholder<1>, int, int))(int, int, int)> > td1' has incomplete type and cannot be defined
  TD<decltype(g)> td1;
                  ^

好吧,不完整的类型错误当然除外。但是在这个错误消息中让我感到好奇的是std::_Bind<void (*(std::_Placeholder<1>, int, int))(int, int, int)>.我可以理解std::_Bind是一个代理类,它定义了operator()并使我们的目的成为可能。但它的模板参数void (*(std::_Placeholder<1>, int, int))(int, int, int)让我惊叹!我应该如何解释它?它在用户土地代码中是否有任何用处?如何使用此声明创建自己的类?

void (*(std::_Placeholder<1>, int, int))(int, int, int)

这声明了一个未命名的函数,它接受三个参数(std::_Placeholder<1>intint(,并返回一个指针,指向一个函数,该函数需要三个int并返回void

让我们简化一点。首先考虑一个简单的函数声明:

void f(int)

现在,在参数声明(函数或模板(中,您可以省略名称,然后得到

void (int) 

如果在函数声明的参数列表中使用,则等效于函数指针void(*)(int)

返回函数指针的函数声明如下:

void (*f(int))(int);
//   ^       ^         <- this pair of parentheses changes
//                        the order in which the declaration is parsed.
//                        Without it, the return type would be `void*`
//                        and you'd get a syntax error

现在你可以删除名称f,你基本上得到你问的相同的东西。

它的用途?显然,这在实现std::bind :)时很有用我现在想不出别的了...

C++11标志着function的出现,这使得定义函数指针变得更加容易:

std::function 的实例可以存储、复制和调用任何可调用目标 - 函数、lambda 表达式、绑定表达式或其他函数对象,以及指向成员函数的指针和指向数据成员的指针。

例如,假设您需要在其中一个函数中获取一个函数指针以string foo(int param) { return to_string(param); }。在 C++11 之前,您的函数需要如下所示:

void bar(string (*func)(int)) { cout << func(13) << endl; }

让我们更进一步,假设您想将foo扩展到:string foo2(int lhs, int rhs) { return to_string(lhs + rhs); } 。但是现在你想把它塞回bar.bar(bind(&foo2, placeholders::_1, 42));执行此操作会给您一个如下错误:

无法将参数 '1' 的 'std::_Bind_helper (*((int, int(, const std:::_Placeholder<1>&, int>::type {aka std::_Bind (*(std::_Placeholder<1>, int(((int, int(>}' 转换为 'std::string (*((int( {aka std::basic_string (*((int(

}' 对于参数 '1' 到 'void bar(std::string (*((int(('

您可以通过创建一个采用实现特定参数的函数来绕过此错误,例如:void bar2(_Bind<string (*(_Placeholder<1>, int))(int, int)> func) { cout << func(13) << endl; }可以使用以下方法成功调用:bar2(bind(&foo2, placeholders::_1, 42)); 。这是特定于实现的原因是类型:_Bind_Placeholder 是非标准的。事实上,bind的回报是:

未指定类型 T 的函数对象

这把我们带到了function.如果尚未关闭函数指针的语法限制,则需要采用function参数来接受由 bind 创建的对象。让我们使用 function 创建一个新bar

void bar3(function<string(int)> func) { cout << func(13) << endl; }

这能够同时接受传统的函数指针和bind函子。此外,它可以处理 lambda,因此您可以执行以下操作: bar3([](int param) { return to_string(param); });

我创建了一个实时示例,因此您可以尝试使用它,希望function对象的好处是显而易见的。

最新更新