如本页http://en.cppreference.com/w/cpp/thread/async所示,C ++ 14中std::async
的签名之一已从C ++ 11版本更改
template< class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
async( Function&& f, Args&&... args );
到
template< class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
async( Function&& f, Args&&... args );
更改是在函数和参数类型传递给std::decay_t
之前应用的std::result_of
(删除引用和cv限定符以及衰减数组/函数到指针)。我不太明白为什么腐烂是有用的。例如,对于函数类型Fn
(可能是闭包类的类型别名),传递Fn
,Fn&&
,const Fn&
等似乎都会产生相同的结果。
有人能给我一个具体的例子,其中衰变是有用的吗?
更新:例如,此代码:
#include <iostream>
#include <type_traits>
int main()
{
auto fn = [](auto x) -> int { return x + 1; };
using Fn = decltype(fn);
using FnRef = Fn&;
using FnCRef = const Fn&;
using FnRRef = Fn&&;
std::cout << std::boolalpha
<< std::is_same<int, std::result_of_t<Fn(int)>>::value << '\n'
<< std::is_same<int, std::result_of_t<FnRef(int)>>::value << '\n'
<< std::is_same<int, std::result_of_t<FnCRef(int)>>::value << '\n'
<< std::is_same<int, std::result_of_t<FnRRef(int)>>::value << '\n';
return 0;
}
将打印出四个true
。
答案 0 :(得分:9)
此更改是对LWG 2021的回应。问题是async
(如bind
等)衰减 - 复制其所有参数,因此如果您在返回类型中未使用decay
,则会出错在参考资格和/或rvalue-ness时返回类型:
struct F {
int operator()() &;
char operator()() &&;
int operator(int& ) const;
char operator(int&& ) const;
};
auto future = std::async(F{}); // actually gives future<int>, but says
// it gives future<char>?
auto future2 = std::async(F{}, 1); // ditto
因为异步的所有参数都是MoveConstructed到它的内部对象,所以你需要巧妙地包装它们以便实际实现参数的rvalue-ness。
这是有道理的 - async
必须在某处存储其参数,如果你传入rvalues,它必须拥有它们的所有权。如果它保留在右值引用上,则底层对象可能会被破坏。但是一旦它将它存储为T
,它就不知道它来自T&
还是T&&
- 它在那时只有一个命名的左值参数。