C++ 类型特征和未赋值上下文

C++ 类型特征和未赋值上下文,c++,c++11,c++14,typetraits,C++,C++11,C++14,Typetraits,cppreference.com说关于类型特征: 如果表达式std::declval=std::declval在未计算的上下文中格式正确,则提供等于true的成员常量值。对于任何其他类型,值为false。类型T和U必须是完整的对象类型、cv void或未知边界的数组。访问检查的执行就像来自与任何一种类型无关的上下文一样 但是代码: template< std::size_t ...indices, std::size_t ...counter > auto invert_indice

cppreference.com说关于类型特征:

如果表达式std::declval=std::declval在未计算的上下文中格式正确,则提供等于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 >{});
工作,尽管功能相反,索引不是constexpr且具有结果类型auto

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

反转索引未计算,但其返回类型已知。由于自动返回类型,它需要查看主体以了解其类型


因此,make_inversed_index_t<10,20,30>是std::index_sequence<30,20,10>,这是一个完整的对象类型。

生成的类型不是可分配对象的一部分。T和U的产生完全独立于is_可赋值的语义

周围的文档描述了它对类型的作用。但是反转索引是通过make_inversed_index_t来计算的,而不是通过is_赋值来计算的。并使反向索引能够清楚地评估反向索引的主体

所有这些都是在将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;
  }
};
它增加了一个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 >{});
在第一种情况下,我们在计算运算符=的主体时得到硬错误。在第二种情况下,SFINAE后卫踢了进来,一切都过去了

因此,即使在未赋值的上下文中,如果函数体的返回类型是auto,那么函数体也会被赋值,至少在实践中是这样

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 >{});