关于获取函数结果类型的各种方法 在一个函数调用结果的类型必须被推断的上下文中,C++似乎更乐意帮助我们,至少提供以下两个解决方案:

关于获取函数结果类型的各种方法 在一个函数调用结果的类型必须被推断的上下文中,C++似乎更乐意帮助我们,至少提供以下两个解决方案:,c++,c++14,typetraits,C++,C++14,Typetraits,类型特征: std::result_of<F(Args...)>::type std::result\u of::type 核心语言语法: decltype(std::declval<F>()(std::declval<Args>()...); decltype(std::declval()(std::declval()…); 我的问题是,两者之间有什么区别吗?是否存在一个上下文,其中一个不能被另一个替换,如果没有,为什么我们需要一个类型特征来完成

类型特征:

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

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

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

    的result\u在应用于给定类型时会产生的返回类型-它甚至在中使用e> invoke
    声明的返回类型。但是,
    invoke
    所涵盖的场景远不止普通的非成员函数调用。您展示的
    decltype(…)
    中的表达式只是的
    结果\u检查的众多表达式之一

    因此,只有当
    F
    被保证为函数对象类型时,您的选项才是等效的。否则
    result\u在
    decltype(…)
    不是:

    struct A {int i;};
    decltype(std::declval<int A::*>()(std::declval<A>())) // error
    std::result_of_t<int A::*(A)> // = int&&, treated as a member access
    
    结构A{int i;};
    DeCype(STD:DeCalvE)(STD::DECVALL)(注意< C++ >代码>代码>友好,如C++ 14,即无效类型导致“ASCODE > DeCype < /代码>的平滑演绎失败。”

    < P> >一些不太有经验的C++程序员,让他们猜测每个代码段的代码。 有多少人第一次正确?有多少人第二次正确

    给这个操作起一个名字会使它更具可读性

    现在,请一些有经验的C++程序员,让他们在不使用RESUTTHORE的情况下得到函数调用的结果类型。有多少人得到正确的答案,并且需要多长时间?

    这已经不是一个简单的元编程了,封装它可以让谷歌更容易发现,也更容易找到正确的方法

    而且,第一个版本要短一些


    所以的结果是非常有用的,因为标准库本身需要它很多次,所以让程序员也可以使用它是很简单的。

    有三个区别

  • 最初,
  • std::result_不要求是SFINAE友好的。因此,如果要在上下文中使用它来验证
    F
    是否可以使用
    Args…
    调用,它将给您一个硬错误,而
    decltype
    使用
    std::declval
    只会导致可能的预期替换失败。修复了本规范旨在使其具有友好性

    但在兼容的C++14编译器上,两者都是SFINAE友好的。
    std::result\u of_t
    实际上是根据后者定义的。From[meta.trans.other]:

    如果表达式
    INVOKE(declval(),declval()…)
    很好 当被视为一个整体时形成的 未赋值的操作数(第5条) 成员类型定义类型应命名 键入
    decltype(调用(declval(),declval()…);
    否则,不得有任何成员 类型

  • 正如
  • result\u的定义中明确指出的那样,
    Fn
    类型可以是任何
    INVOKE
    -able,而显式调用
    std::declval()
    只对函数和函数对象有效。因此,如果您有:

    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
    
    这导致SFINAE失败(至少这不是一个硬错误),因为我们必须形成类型
    int()()
    ——一个返回函数的空函数。从技术上讲,我们编写的代码不正确。应该是:

    template <class F, class R = std::result_of_t<F&()>>
    R call_fixed(F& f) { return f(); }
    
    模板
    R调用_fixed(F&F){return F();}
    
    这是可行的。但如果我们对德克瓦尔犯了同样的错误,我们会没事的:

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

    事实上,我不确定它是否是一个dupe。通常是关于
    decltype
    。这一个是专门在函数调用的上下文中。第三个:如果
    F
    Args
    中的一个是抽象的,或者
    F
    是一个函数类型,
    result\u
    是无效的,但是
    decltype
    declval
    可以正确工作y、 (解决方法是使用
    result\u@Barry我相信形成类型“函数返回函数”或“函数[按值获取抽象类型]按值返回抽象类型”是不可能的。@Columbo这很不幸。@Barry可能是在变量模板出现之前引入
    result\u的(最初是在年提出的)。为了传递所需的信息,他们认为使用复合函数类型既有效(与某些元组类模板相反),又有简洁的语法。后者仍然有效,IMO超过了这些特殊情况。@Columbo是的,但我不完全理解这一点。
    
    template <class F, class R = decltype(std::declval<F>()())>
    R call_declval(F& f) { return f(); }