c++ - 关于获取函数结果类型的各种方法

标签 c++ c++14 typetraits

在必须推导函数调用结果类型的上下文中,C++ 似乎更乐于帮助我们,提供(至少据我所知是以下)两种解决方案:

  • result of类型特征:

    std::result_of<F(Args...)>::type
    
  • 核心语言语法:

    decltype(std::declval<F>()(std::declval<Args>()...); 
    

我的问题是,两者之间有什么区别吗?是否存在一个不能被另一个替代的上下文,如果不是,为什么我们需要一个类型特征来做一些语言可以开箱即用的事情?

最佳答案

存在三个差异。

  1. 最初,std::result_of不需要对 SFINAE 友好。因此,如果要在上下文中使用它来验证 F可以用 Args... 调用,它会给你一个硬错误,而 decltypestd::declval只会导致可能的预期替代失败。 N3462修复了规范,使其对 SFINAE 友好。

    虽然在兼容的 C++14 编译器上,两者都是 SFINAE 友好的。 std::result_of_t<Fn(ArgsTypes...)>实际上是根据后者定义的。来自 [meta.trans.other]:

    If the expression INVOKE (declval<Fn>(), declval<ArgTypes>()...) is well formed when treated as an unevaluated operand (Clause 5), the member typedef type shall name the type decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...)); otherwise, there shall be no member type.

  2. 正如result_of的语言定义所明确的那样, 类型 Fn可以是任何东西INVOKE -able,而显式调用std::declval<F>()仅适用于函数和函数对象。所以如果你有:

    using F = decltype(&X::bar);
    using T1 = std::result_of_t<F(X*)>;                        // ok
    using T2 = decltype(std::declval<F>()(std::declval<X*>()); // not ok
    
  3. 对于某些类型,std::result_of由于指定某些 type-id 是非法的(参见 my related question ),因此实际上不起作用。这些类型正在使用 F 的函数(与函数的指针/引用相反)或对任何 Args... 使用抽象类.因此,考虑一些看似无害的事情:

    template <class F, class R = std::result_of_t<F()>>
    R call(F& f) { return f(); }
    
    int foo();
    call(foo); // error, unresolved overload etc.
    

    这会导致 SFINAE 失败(至少这不是硬错误),因为我们必须形成类型 int()() - 返回函数的空函数。现在,从技术上讲,我们错误地编写了代码。应该是:

    template <class F, class R = std::result_of_t<F&()>>
    R call_fixed(F& f) { return f(); }
    

    这行得通。但是如果我们在 declval 上犯了同样的错误,我们会没事的:

    template <class F, class R = decltype(std::declval<F>()())>
    R call_declval(F& f) { return f(); }
    

关于c++ - 关于获取函数结果类型的各种方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35834026/

相关文章:

c++ - 与 gfortran 链接时未定义对 `std::chrono::_V2::system_clock::now()' 的引用

c++ - 为两种 vector 类型或一种 vector 类型与标量类型之间的二元运算结果确定正确的大小类型

c++ - 为什么 strlen 对我不起作用?

c++ - 当警告为错误时使用 [[deprecated]] 属性 (-Werror)

c++ - 迭代有序容器与无序容器

c++ - 使用不同功能的队列中的打印元素不会在_start程序中全局清空队列。还有更多解释吗?

c++ - 从实现中解耦类型特征定义

c++ - 如何在C++中声明Magnitude类型?

c++ - 如何将对象数组作为参数传递给模板

c++ - Qt 调试 : I am implementing a Qt thread class that is not being recognized when used, 我做错了什么?