传递给std :: result_of之前的衰减类型

Ziz*_*Tai 11 c++ templates c++11 c++14

如本页http://en.cppreference.com/w/cpp/thread/async所示std::async,C++ 14中的一个签名已从C++ 11版本更改

template< class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
    async( Function&& f, Args&&... args );
Run Code Online (Sandbox Code Playgroud)

template< class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
    async( Function&& f, Args&&... args );
Run Code Online (Sandbox Code Playgroud)

更改是在std::decay_t传递给函数和参数类型之前应用于函数和参数类型的s(将参考和cv限定符和衰减数组/函数移除到指针中)std::result_of.我不太明白为什么腐烂是有用的.例如,对于一个功能类型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;
}
Run Code Online (Sandbox Code Playgroud)

将打印出四个true.

Bar*_*rry 9

这一变化是对LWG 2021的回应.问题是async(比如bind等)衰减 - 复制它的所有参数,所以如果你没有decay在返回类型中使用,那么当涉及到ref-qualifications和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
Run Code Online (Sandbox Code Playgroud)

因为异步的所有参数都是MoveConstructed到它的内部对象,你需要巧妙地包装它们以实际实现参数的rvalue-ness.

这是有道理的 - async 必须在某处存储其参数,如果你传入rvalues,它必须拥有它们的所有权.如果它保留在右值引用上,则底层对象可能会被破坏.但是一旦它将它存储为a T,它就不知道它来自a T&还是a T&&- 它只是在那时有一个命名的左值参数.

  • 需要注意的是,新版本意味着它`move`s的功能和参数进行其内部存储的进入呼叫表达,这也是做正确的事情. (2认同)
  • @ZizhengTai因为他们搬进来 - 作为右值.如果你没有`decay_t`,你将检查返回类型,好像它们可能是左值. (2认同)