【问题标题】:Type traits and unevaluated context类型特征和未评估的上下文
【发布时间】:2015-06-25 08:47:38
【问题描述】:

cppreference.com 关于is_assignable<T,U> type-trait 的说法是:

如果表达式std::declval<T>() = std::declval<U>() 在未计算的上下文中格式正确,则提供等于true 的成员常量值。对于任何其他类型,值为 false。 T 和 U 类型必须是完整的对象类型、cv void 或未知边界的数组。访问检查就像来自与任一类型无关的上下文一样执行。

但是代码:

template< std::size_t ...indices, std::size_t ...counter >
auto
invert_indices(std::index_sequence< counter... >)
{
    constexpr std::size_t size = sizeof...(counter);
    constexpr std::size_t inverted[size]{indices...};
    return std::index_sequence< inverted[size - 1 - counter]... >{};
}

template< std::size_t ...indices >
auto
invert_indices()
{
    return invert_indices< indices... >(std::make_index_sequence< sizeof...(indices) >{});
}

template< std::size_t ...indices >
using make_inverted_indices_t = decltype(invert_indices< indices... >());

using L = make_inverted_indices_t< 10, 20, 30 >;
using R = std::index_sequence< 30, 20, 10 >;
static_assert(std::is_same< L, R >{});
static_assert(std::is_assignable< make_inverted_indices_t< 10, 20, 30 > &, R >{});
static_assert(!std::is_assignable< make_inverted_indices_t< 10, 20, 30 > &, int >{});

工作,尽管函数 invert_indices 不是 constexpr 并且结果类型为 auto

对于未评估的上下文,在decltype 工作期间是否仍允许查看函数体?

【问题讨论】:

    标签: c++ c++11 c++14 typetraits


    【解决方案1】:

    invert_indices&lt; indices... &gt;() 没有被评估,但它的返回类型是已知的。由于auto 返回类型,它需要查看body 才能知道它的类型。

    所以make_inverted_indices_t&lt; 10, 20, 30 &gt;std::index_sequence&lt; 30, 20, 10 &gt;,这是一个完整的对象类型。

    【讨论】:

      【解决方案2】:

      产生的类型不是is_assignable 的一部分。 TU 的生成完全独立于 is_assignable 的语义。

      is_assignable 周围的文档描述了它对类型的作用。但是invert_indexesmake_inverted_indexes_t 评估,而不是is_assignable。而make_inverted_indexes_t 清楚地评估了invert_indexes 的正文。

      所有这些都发生在 is_assignable 被传递类型之前。

      如果我们改为查看 is_assignable 传递类型后发生的事情,我在这里创建一个玩具类型:

      template<size_t N>
      struct foo {
        template<std::size_t K>
        decltype(auto) operator=(foo<K> const& in){
          static_assert( (K<N) );
          return in;
        }
      };
      

      在直接上下文中,它看起来可以被分配给其他foo,并且

      template<size_t N>
      struct foo {
        template<std::size_t K, class=std::enable_if_t<(K<N)>>
        decltype(auto) operator=(foo<K> const& in){
          static_assert( (K<N) );
          return in;
        }
      };
      

      增加了一个 SFINAE 守卫。如果我们运行这些测试:

      using L = foo<10>;
      using R = foo<11>;
      static_assert(!std::is_same< L, R >{});
      static_assert(!std::is_assignable< L &, R >{});
      static_assert(std::is_assignable< R &, L >{});
      static_assert(!std::is_assignable< L &, std::string >{});
      

      在第一种情况下,我们会在评估 operator= 的主体时遇到硬错误。在第二种情况下,SFINAE 后卫介入,一切都过去了。

      Live example.

      因此,即使在未评估的上下文中,如果函数体的返回类型为 auto,至少在实践中也会对其进行评估。

      【讨论】:

        猜你喜欢
        • 2013-03-05
        • 2012-10-24
        • 1970-01-01
        • 1970-01-01
        • 2016-05-19
        • 1970-01-01
        • 2016-03-22
        • 2020-02-04
        • 2023-03-18
        相关资源
        最近更新 更多