代码之家  ›  专栏  ›  技术社区  ›  David Bien

declval<_Xp(&)()>()()-这在下面的上下文中意味着什么?

  •  1
  • David Bien  · 技术社区  · 1 年前

    这是来自: https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/include/std/type_traits

      template<typename _Xp, typename _Yp>
        using __cond_res
          = decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()());
    ...
      template<typename _Tp1, typename _Tp2>
        struct __common_reference_impl<_Tp1, _Tp2, 3,
                       void_t<__cond_res<_Tp1, _Tp2>>>
        { using type = __cond_res<_Tp1, _Tp2>; };
    

    我想弄清楚 _Xp(&)() 是-是函数调用签名吗?即建造师?真的没有道理。那里似乎有一个匿名变量名,即:

    _Xp(&anon)()
    

    不知怎么的,我仍然无法理解它,在过去的34年里,我一直在编写C++。

    如有任何解释,不胜感激。谢谢

    3 回复  |  直到 1 年前
        1
  •  6
  •   Barry    1 年前

    tl;博士我们需要一种方法来生成具有类型和值类别的表达式 T ,而不是类型和值类别 T&& ,所以我们不能只使用 std::declval<T>() 而是需要做些别的事情。


    重点是:

      template<typename _Xp, typename _Yp>
        using __cond_res
          = decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()());
    

    就是给你 false ? x : y 哪里 x 是类型和值类别的表达式 _Xp y 是类型和值类别的表达式 _Yp

    条件运算符(通常称为三元运算符), ?: ,是一个极其复杂的语言特征。这是语言中prvalues和xvalues之间实际存在差异的地方之一。

    实现这一点的天真方法是:

      template<typename _Xp, typename _Yp>
        using __cond_res
          = decltype(false ? declval<_Xp>() : declval<_Yp>());
    

    因为,嗯,不是这样吗 declval<T>() 是为了,给你一个 T ?但实际上,这里有一个缺陷,因为 declval 未指定为:

    template <typename T>
    auto declval() -> T;
    

    它被指定为( add_rvalue_reference_t<T> 而不是 T&& 正确处理 void )以下为:

    template <typename T>
    auto declval() -> std::add_rvalue_reference_t<T>;
    

    因此 __cond_res<int, int> __cond_res<int&&, int&&> 将无法区分,即使第一个需要 int 而后者需要 int&&


    因此,我们需要一种方法来实际生成类型的任意表达式 T 一种方法是:

    template <typename T>
    auto better_declval() -> T;
    
    template<typename _Xp, typename _Yp>
      using __cond_res
        = decltype(false ? better_declval<_Xp>() : better_declval<_Yp>());
    

    这是有效的。

    另一种选择是生成一个函数的实例 T 然后调用它 declval<_Xp(&)()>()() dos-为您提供一个对null函数的引用,该函数返回 _Xp公司 ,然后调用它,给您一个 _Xp公司 (属于正确的值类别)。

    在这种情况下,与 better_declval 方法,但事实证明,这种模式在其他情况下也很有用。类似概念:

    template <typename T>
    concept something = requires (T(&obj)()){
        f(obj());
    };
    

    在这里,我有一个概念,检查我是否可以打电话 f 具有类型的表达式 T ,包括正确区分prvalues和xvalues。以上是我所知道的实现这一目标的最方便的方法。诚然,这是不幸的。

    您还可以执行以下操作:

    template <typename T>
    concept something = requires {
        f(better_declval<T>());
    };
    

    我想这取决于你的观点,以及你需要使用多少次 obj

    一旦你看到这个 T(&)() 在概念上下文中使用的模式,这是一个熟悉的模式,所以一致地使用它是有意义的。

        2
  •  5
  •   Drew Dormann    1 年前

    下降<_Xp(&)()>这是什么意思

    _Xp(&)() 是对不带参数的函数的引用。

    declval<_Xp(&)()>() (含义 std::decvlval )是此函数的一个假设实例。

    declval<_Xp(&)()>()() 正在调用该假设实例,生成一个返回值。

    总的来说,它意味着“将通过调用类型为的函数返回的值 _Xp

        3
  •  4
  •   Jan Schultke    1 年前
    • _Xp(&)() 是对不带参数并返回的函数的引用 _Xp
    • declval<_Xp(&)()>()() 返回这样一个函数引用并调用它,结果 _Xp公司
    decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()())
    

    …是一种常见的 _Xp公司 _Yp ,遵循条件运算符的规则。

    只是使用的区别 declval<_Xp>() 是吗 declval 不返回值,而是返回 std::add_rvalue_reference_t<_Xp>

    您可以看到,此类型别名用于确定两种类型之间的公共引用:

    template<typename _Tp1, typename _Tp2>
    struct __common_reference_impl<_Tp1, _Tp2, 3, void_t<__cond_res<_Tp1, _Tp2>>>
    { using type = __cond_res<_Tp1, _Tp2>; };
    

    注意:您可以使用 cdecl+ 以更好地理解C和C++类型语法。