C++ 无法使用自动调用std::invoke();通过std::ref()的参数
我正在尝试创建一个C++ 无法使用自动调用std::invoke();通过std::ref()的参数,c++,c++11,lambda,c++17,C++,C++11,Lambda,C++17,我正在尝试创建一个调用程序对象,该对象存储一个functor和该functor的一组参数-全部按值(用于线程)。 Invoker::operator()()将使用复制的参数调用存储的functor 到目前为止,一切正常,直到人们尝试使用std::ref(variable)通过auto&传递参数。具体来说,此代码应该可以工作,但它不会使用给定的错误消息进行编译: int var = 0; Invoker{ [](auto& r) { printf("%d\n", r
调用程序
对象,该对象存储一个functor和该functor的一组参数-全部按值(用于线程)。
Invoker::operator()()
将使用复制的参数调用存储的functor
到目前为止,一切正常,直到人们尝试使用std::ref(variable)
通过auto&
传递参数。具体来说,此代码应该可以工作,但它不会使用给定的错误消息进行编译:
int var = 0;
Invoker{
[](auto& r) {
printf("%d\n", r);
}, std::ref(var)
}();
我希望它的工作方式类似于std::thread
在本例中的工作方式。
错误消息是:
获取此问题的联机版本。错误消息表明,auto&
的推断类型是std::reference\u wrapper&
,而它应该是int&
。不幸的是,我不能想出解决这个问题的办法
编辑:
正如评论所显示的,这个表达
int var = 5;
std::thread{ [](auto& r) { printf("%d\n", r); }, std::ref(var) };
仅编译为
gcc>=7.1.0
。我希望看到这个主题的详细阐述,特别是如果这是C++行为的正确行为。 <代码>调用> <代码>一般不拆开<代码>参考文献包装> <代码>参数;它们按原样使用(有一个例外与此无关:如果调用指向成员的指针,并将引用_包装器
作为第一个参数,则该参数将被展开)。因此,invoke([](auto&){},std::ref(var))
将尝试使用右值引用\u包装
调用lambda,这对于尝试将右值绑定到左值引用来说是格式错误的
使用
std::thread
观察到的行为是已修复的。简而言之,libstdc++的std::thread
将提供的参数存储在元组中,该元组是(错误地)用make\u tuple
构造的(它打开reference\u wrapper
s)。INVOKE
通常不打开reference\u wrapper
参数;它们按原样使用(有一个例外与此无关:如果调用指向成员的指针,并将引用_包装器
作为第一个参数,则该参数将被展开)。因此,invoke([](auto&){},std::ref(var))
将尝试使用右值引用\u包装
调用lambda,这对于尝试将右值绑定到左值引用来说是格式错误的
使用std::thread
观察到的行为是已修复的。简而言之,libstdc++的std::thread
将提供的参数存储在一个元组中,该元组是(错误地)用make\u tuple
构造的(打开reference\u wrapper
)对auto
的推断使用相同的规则进行模板参数推断,这不允许隐式转换。问题可通过int n=5再现;自动&r=ref(n)代码>。由于ref(n)
是一个右值,因此它不能绑定到左值引用。@0x499602D2不过,当使用std::thread
时,它仍能正常工作。我想复制一下behaviour@nyronium否,std::thread([](auto&ref){},std::ref(var))代码>从不编译。@如果你错了。请参见。auto
的报告为推断使用相同的模板参数推断规则,这不允许隐式转换。问题可通过int n=5再现;自动&r=ref(n)代码>。由于ref(n)
是一个右值,因此它不能绑定到左值引用。@0x499602D2不过,当使用std::thread
时,它仍能正常工作。我想复制一下behaviour@nyronium否,std::thread([](auto&ref){},std::ref(var))代码>从不编译。@如果你错了。见。报告为
template<typename... Args>
struct Invoker {
std::tuple<std::decay_t<Args>...> args;
explicit Invoker(Args... args)
: args(std::forward<Args>(args)...)
{ }
template<size_t... Indices>
void _Invoke(std::index_sequence<Indices...>) {
std::invoke(std::get<Indices>(std::move(args))...);
}
void operator()() {
_Invoke(std::make_index_sequence<std::tuple_size_v<decltype(args)>>{});
}
};
/* Invoker deduction guide (perfectly forward any parameters with full type!) */
template<typename Function, typename... Args>
Invoker(Function&&, Args&&...) -> Invoker<Function&&, Args&&...>;
int var = 5;
std::thread{ [](auto& r) { printf("%d\n", r); }, std::ref(var) };