标准::绑定和完美转发
std::bind and perfect forwarding
以下代码无法编译:
#include <functional>
template<class ...Args>
void invoke(Args&&... args)
{
}
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<Args...>, std::forward<Args>(args)...);
binder();
}
int main()
{
int a = 1;
bind_and_forward(a, 2);
}
如果我理解正确,原因如下:std::bind
复制其参数,当调用binder
的operator()
时,它会将所有绑定参数作为左值传递 - 即使是那些输入bind
作为右值的参数。但是invoke
是为原始参数实例化的,它不能接受binder
试图传递它的内容。
这个问题有什么解决方案吗?
你的理解是正确的 - bind
复制它的参数。因此,您必须提供将在左值上调用的invoke()
的正确重载:
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<Args&...>, std::forward<Args>(args)...);
^^^^^^^^
binder();
}
这适用于大多数类型。在 [func.bind.bind] 中列举了一些operator()
例外,其中Arg&
是不够的。正如您所指出的,其中之一是 std::reference_wrapper<T>
.我们可以通过用类型特征替换上面的Args&
用法来解决这个问题。通常,我们只会添加一个左值引用,但对于reference_wrapper<T>
,我们只需要T&
:
template <typename Arg>
struct invoke_type
: std::add_lvalue_reference<Arg> { };
template <typename T>
struct invoke_type<std::reference_wrapper<T>> {
using type = T&;
};
template <typename T>
using invoke_type_t = typename invoke_type<T>::type;
将其重新插入原始解决方案,我们也得到了适用于reference_wrapper
的东西:
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<invoke_type_t<Args>...>,
// ^^^^^^^^^^^^^^^^^^^
std::forward<Args>(args)...);
binder();
}
当然,如果Arg
中的一个是占位符,这无论如何都行不通。如果它是一个绑定表达式,你也必须编写其他东西。
相关文章:
- 将函数参数完美转发到函数指针:按值传递呢?
- C++20理念:要求表达和完美转发
- 完美的转发和构造函数
- 我可以列表初始化 std::vector 并完美转发元素吗?
- 返回值的完美转发?
- 使用衰减与完美转发
- 可变参数模板:将整数参数完美转发到 lambda
- 完美转发C++重载和模板化函子及其参数
- 在完美转发中需要衰减
- C++完美转发:如何避免悬空引用
- 完美的对象转发阵列
- 无法理解一段具有完美转发和省略号的C++代码
- 在编写包装现有函数并检查错误的模板函数时,如何使用完美转发?
- 完美转发可变参数模板模板
- 在完美转发函数中公开参数类型,避免代码重复
- 完美的转发构造函数和已删除的构造函数
- 完美的转发功能推断出冲突错误
- 使用完美转发的模板转换构造函数
- 完美转发使用结构化绑定声明的变量
- 完美转发常量参数以进行持续评估