【发布时间】:2018-02-23 13:29:52
【问题描述】:
我正在尝试创建一个Invoker 对象,它同时存储一个函子和该函子的一组参数 - 全部按值(用于线程)。
Invoker::operator()() 将使用复制的参数调用存储的仿函数。
到目前为止一切正常,直到有人尝试使用std::ref(variable) 通过auto& 传递参数。具体来说,这段代码应该可以工作,但它不会使用给定的错误消息进行编译:
int var = 0;
Invoker{
[](auto& r) {
printf("%d\n", r);
}, std::ref(var)
}();
我希望它的工作方式类似于 std::thread 在此示例中的工作方式。
错误信息是:
test.cpp:65:14: error: no matching function for call to ‘invoke(std::__tuple_element_t<0, std::tuple<main()::<lambda(auto:1&)>, std::reference_wrapper<int> > >, std::__tuple_element_t<1, std::tuple<main()::<lambda(auto:1&)>, std::reference_wrapper<int> > >)’ std::invoke(std::get<Indicies>(std::move(args))...); ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
我现在的Invoker班级:
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&&...>;
See here 获取此问题的在线版本。错误消息表明,auto& 的推导类型是 std::reference_wrapper<int>&,而它应该是 int&。不幸的是,我无法想出解决这个问题的办法。
编辑:
如 cmets 所示,表达式
int var = 5;
std::thread{ [](auto& r) { printf("%d\n", r); }, std::ref(var) };
仅使用 gcc >= 7.1.0 编译。我很高兴看到有关此主题的详细说明,特别是如果这是 c++ 标准的正确行为。
【问题讨论】:
-
auto的推导使用相同的模板参数推导规则,这不允许隐式转换。可以使用int n = 5; auto& r = ref(n);重现该问题。由于ref(n)是一个右值,它不能绑定到左值引用。 -
@0x499602D2 尽管如此,当使用
std::thread时它可以正常工作。我想复制这种行为 -
@nyronium 不,
std::thread([] (auto &ref) {}, std::ref(var));从不编译。 -
@liliscent 你错了。见proof。