回调中的占位符_1是如何工作的
How placeholders as _1 in a callback works?
编译器如何解释符号_1
,以及绑定是如何发生的?考虑以下示例:
class A {
public:
boost::function<void (int x)> g;
};
class B {
public:
B() {}
static void foo(int i) { cout << "Hack: " << i <<endl; }
};
int main() {
A a;
a.g = boost::bind(B::foo,_1);
a.g(2);
return 0;
}
boost::bind(B::foo,_1);
行内部发生了什么魔法?
_1
是如何映射到下一行a.g(2);
中传递的参数的?
输出:
破解:2
我将尽我所能进行解释。首先,_1
只是一个全局变量。在这方面,它没有什么特别的,它也可以被命名为其他任何东西——placeholder1
或SergeyA
。然而,像_1
这样的名称很短,有很好的理解意义,并且以_
开头,这降低了它与程序中其他全局名称冲突的可能性。
神奇之处在于这个变量的类型。它有一种特殊的类型,反映在生成的bind*
对象中。稍后,当调用operator()
时,该类型被识别为从operator()
参数中获取一个参数。
以下是一些类似C++的伪代码,虽然不正确,但很有说明性:
template<class F, class... ARG>
struct bound {
bound(F f, ARGS&&... args) : bound_args(args...), functor(f) { }
std::tuple<ARG...> bound_args;
template<class... T>
void operator()(T&&... args);
F f;
};
template<class F, class... T>
auto bind(F f, T&& args) {
return bound<std::remove_reference_t<T>...>(f, args...);
}
现在,让我们介绍一种占位符类型。
template<size_t N>
struct placeholder {
enum { position = N; };
template<class...T>
auto operator()(T&&... args) {
return std::get<position>(std::make_tuple(arg...));
}
};
placeholder<0> _1;
placeholder<1> _2;
到目前为止还不错。现在,让我们看看operator()是如何实际处理绑定对象的:
template<class... BOUND_ARGS>
template<class... CALL_ARGS>
void bound_object<BOUND_ARGS...>::operator() (CALL_ARGS&&... args) {
call_impl(args..., make_index_sequence<sizeof...(BOUND_ARGS)>{});
}
这里需要make_index_sequence来将元组值提取到函数参数中,所以不要太关注它。这里是call_impl;
template<class... BOUND_ARGS>
template<class... CALL_ARGS, size_t... ix>
void bound_object<BOUND_ARGS...>::call_impl(CALL_ARGS&&... args, std::index_sequence<ix...>) {
f(to_arg().(std::get<ix>(bound_args), args...)...);
}
最后一块拼图是to_arg
:
template<class B, class... ARGS>
auto to_arg(B&& b, ARGS... args) {
return b;
}
template<class... ARGS>
auto to_arg(placeholder<0> p, ARGS&&... args) {
return p(args);
}
template<class... ARGS>
auto to_arg(placeholder<1> p, ARGS&&... args) {
return p(args);
}
这里的整个to_arg
是根据绑定参数类型为您提供绑定参数或提供的参数之一。在上面的例子中,我使用了3个重载,因为你可以部分专门化一个函数,但当然,把它放在一个类中并部分专门化这个类会更有意义。
相关文章:
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 链表c++插入,所有情况都已检查,但没有任何工作
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?