result_of <F(Args ...>和decltype <f(args ...)>之间有什么区别?

Kno*_*abe 14 c++ c++11

我看到它std::async的具体说明如下:

template <class F, class... Args>                   // copied out of the standard
future<typename result_of<F(Args...)>::type>
async(F&& f, Args&&... args);
Run Code Online (Sandbox Code Playgroud)

我曾预料到它会被声明为:

template <class F, class... Args>
auto async(F&& f, Args&&... args) ->
  future<decltype(forward<F>(f)(forward<Args>(args)...)>;
Run Code Online (Sandbox Code Playgroud)

那是相同的,还是有某种方式使用它比使用result_of更好decltype?(我理解它result_of适用于类型,同时decltype适用于表达式.)

Luc*_*ton 11

您的版本不适用于例如指向成员的指针.更接近但仍然不准确的版本是:

template <class F, class... Args>
auto async(F&& f, Args&&... args)
-> future<decltype( ref(f)(forward<Args>(args)...) )>;
Run Code Online (Sandbox Code Playgroud)

剩下的唯一区别std::result_of是,它将functor转换为左值(您的版本也共享的问题).换句话说,这种呼叫(通过一个std::reference_wrapper<F>)的结果是typename std::result_of<F&(Args...)>::type.

这是一个尴尬的局面,其中标准库的几个组成部分(仅举几例,除了那些我们刚刚见证:std::thread,std::bind,std::function)在一个难以捉摸的条款规定INVOKE(F,A0,A1,..., aN)伪表达式,它不完全等同于f(a0, a1, ... aN).由于std::result_of是其中一个组件,并且实际上用于计算INVOKE的结果类型,这就是您注意到的差异.

因为没有std::invokestd::result_of类型特征串联的结果,我认为后者仅用于描述例如相关标准库组件的返回类型,当您的代码调用它们时.如果你想要一种简洁的,自我记录的写作方式,例如返回类型(一个非常有价值的可读性目标,与洒水decltype无处不在),那么我建议你编写自己的别名:

template<typename F, typename... A>
using ResultOf = decltype( std::declval<F>()(std::declval<A>()...) );
Run Code Online (Sandbox Code Playgroud)

(如果你想要使用别名ResultOf<F(A...)>而不是ResultOf<F, A...>那么你需要一些机制来模拟匹配函数签名.)

这个别名的另一个好处是它与SFINAE友好,不像std::result_of.是的,这是它的一个缺点.(公平地说,虽然已经对即将推出的标准进行了修改,但实施方案已经适用了.)

如果你使用这样的特性,你不会错过任何东西,因为你可以通过调整成员的指针std::mem_fn.


Naw*_*waz 5

从功能的角度来看,没有任何区别.但是,该decltype版本使用trailing-return-type,这与编程的观点有一点不同.

在C++ 11中,std::result_of并非绝对必要,可以使用decltype,就像你使用的方式一样.但是std::result_of向后兼容第三方库(较旧的),例如Boost result_of.但是,我没有看到太多的优势.

就个人而言,我更喜欢使用,decltype因为它更强大,适用于任何实体,而result_of只适用于可调用实体.所以,如果我使用decltype,我可以随处使用它.但是result_of,我偶尔会切换到decltype(也就是说,当实体不可调用时).在github上看到这个decltype在所有函数的返回类型中使用的地方.


Dan*_*rey 5

你的问题已经有了不同之处:"我理解它result_of适用于类型,而decltype适用于表达式."

它们都提供相同的功能(std::result_of甚至可以用decltype现在的方式实现),并且您的示例的差异大部分都不存在,因为您已经拥有构建表达式所需的变量.

也就是说,当你只有类型时,差异归结为语法糖.考虑:

typename std::result_of< F( A, B, C ) >::type
Run Code Online (Sandbox Code Playgroud)

decltype( std::declval<F>()( std::declval<A>(), std::declval<B>(), std::declval<C>() )
Run Code Online (Sandbox Code Playgroud)

请记住,std::result_of在这些情况下,这是一个选项.

请注意,也有一些情况decltype可以以不能使用的方式使用std::result_of.考虑一下decltype( a + b ),就我所知,你找不到F创建一个等价物std::result_of< F( A, B ) >.