我正在尝试创建一个Invoker
对象,该对象为该仿函数存储仿函数和一组参数 - 全部按值(用于线程)。
Invoker::operator()()
将使用复制的参数调用存储的仿函数。
到目前为止一切正常,直到尝试使用auto&
std::ref(variable)
传递参数。具体来说,这段代码应该可以工作,但不会使用给定的错误消息进行编译:
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&
。不幸的是,我无法想出解决这个问题的方法。
如评论所示,表达式
int var = 5;
std::thread{ [](auto& r) { printf("%d\n", r); }, std::ref(var) };
仅与gcc >= 7.1.0
一起编译。我很高兴看到有关这个主题的详细说明,特别是如果这是c ++标准的正确行为。
答案 0 :(得分:5)
INVOKE
通常不会打开reference_wrapper
个参数;它们按原样使用(这里有一个例外:如果你调用一个指向成员的指针,其中reference_wrapper
作为第一个参数,那么该参数是unwrapped)。因此,invoke([](auto&){}, std::ref(var));
将尝试使用右值reference_wrapper
来调用lambda,这对于尝试将右值绑定到左值引用而言是错误的。
std::thread
观察到的行为是libstdc++ bug,已修复。简而言之,libstdc ++的std::thread
将提供的参数存储在tuple
中,该make_tuple
({错误地)用reference_wrapper
构建(解包WITH CTE
AS (SELECT Row_number()
OVER (
partition BY Month(AffectedDate)
ORDER BY AffectedDate DESC) rn,
[ItemKey],
[Location],
[QtyOnHand],
[UpdatedOnHandQty],
AffectedDate
FROM [Test].[dbo].[INCos]
WHERE ItemKey = '20406')
SELECT *
FROM CTE
WHERE rn = 1
s)。