输入特征和未评估的上下文

时间:2015-06-25 08:47:38

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

cppreference.com关于is_assignable<T,U>类型特征说:

  

如果表达式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 >{}); 在未评估的上下文中格式正确,则提供成员常量值等于true。对于任何其他类型,值为false。类型T和U必须是完整的对象类型,cv void或未知边界的数组。访问检查的执行方式与从任一类型无关的上下文一样。

但是代码:

invert_indices

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

对于未评估的上下文,是否仍允许在self.topTextView = [[MBTextViewController alloc] initWithNibName:@"MBTextViewController" bundle:nil]; 工作期间查看函数体?

2 个答案:

答案 0 :(得分:2)

invert_indices< indices... >()未评估,但其返回类型已知。由于auto返回类型,它需要查看正文以了解其类型。

所以make_inverted_indices_t< 10, 20, 30 >std::index_sequence< 30, 20, 10 >,这是一个完整的对象类型。

答案 1 :(得分:2)

生成的类型不属于is_assignableTU完全独立于is_assignable的语义而生成。

is_assignable周围的文档描述了它对类型的作用。但invert_indexes评估的是make_inverted_indexes_t,而不是is_assignablemake_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,则至少在实践中会对函数体进行求值。