【问题标题】:Creating an index_sequence of N zeros创建一个包含 N 个零的 index_sequence
【发布时间】:2018-09-06 23:17:00
【问题描述】:

我一直在尝试编写 zero_sequence 类型,它要么创建指定数量的零的 index_sequence,要么使用现有的 index_sequence 生成一个具有相同数量值但全为零的新值。我很困惑为什么会这样:

template<typename> struct zero_sequence;
template<size_t...I> 
struct zero_sequence<index_sequence<I...>> : index_sequence<(I*0u)...>{};

int main( int argc, char *argv[] ) {

  using A  = index_sequence<0,1,2,3,4>;
  using B  = make_index_sequence<5>;
  using A0 = zero_sequence<A>;
  using B0 = zero_sequence<B>;

  A a;  B b; 

  cout <<< std::is_same<A,B>::value << endl; // is false

  A0 a0; 
  B0 b0;  // < error implicit instantiation of undefined template
  return 0;
}

我不明白为什么这两种情况不同(在 Mac Clang llvm 9.0.0 上)。

如果与解释此行为有关,我将在 C++11 中使用 index_sequencemake_index_sequence 的以下实现 I think I got it from here

template<typename Integer, Integer... I>
struct integer_sequence {
  using type = integer_sequence;
  using value_type = Integer;
  static constexpr size_t size() noexcept { return sizeof...(I); }
};

template<size_t... Ints> using index_sequence = integer_sequence<size_t, Ints...>;

template <typename,typename> struct _merge_and_renumber;

template <size_t... I1, size_t... I2>
struct _merge_and_renumber<index_sequence<I1...>,index_sequence<I2...>> 
  : index_sequence<I1..., (sizeof...(I1)+I2)...> {};

template <size_t N>
struct make_index_sequence
  : _merge_and_renumber<typename make_index_sequence<N/2>::type,
                        typename make_index_sequence<N - N/2>::type> {};

template<> struct make_index_sequence<0> : index_sequence<> {};
template<> struct make_index_sequence<1> : index_sequence<0> {};

【问题讨论】:

  • 我得到的唯一错误是cout之后的&lt;&lt;&lt;? (gcc 7.2 和 clang 4.0 都适合我)
  • 其实等一下,C++14里加了integer_sequence,你真的用的是C++11吗?
  • 现场示例:gcc-5.2clang 3.5
  • 对,但它们仍然是不同的类型。模板类型匹配不像函数重载解析那样起作用,它必须是完全匹配的。

标签: c++ c++11 variadic-templates template-meta-programming template-specialization


【解决方案1】:

我建议zero_sequence 完全不同:不是struct,而是基于decltype()std::declval() 和仅声明的辅助函数的using(遵循std::declval() 示例。

我的意思是……如果你定义了以下辅助函数

template <std::size_t ... Is>
constexpr auto zeHelper (index_sequence<Is...> const &)
   -> decltype( index_sequence<(Is,0u)...>{} );

zero_sequence可以定义为

template <typename T>
using zero_sequence = decltype(zeHelper(std::declval<T>()));

您可以同时声明a0b0

A0 a0; 
B0 b0; // now works

编译也没有问题

static_assert( std::is_same<A0, B0>::value, "!" );

我很困惑为什么会发生这种情况 [...] 我不明白为什么这两种情况不同

zero_sequence 模板结构特化的问题

template<size_t...I> 
struct zero_sequence<index_sequence<I...>> : index_sequence<(I*0u)...>{};

是不是也有通用版(未实现,但有)

template<typename> struct zero_sequence;

因此,当您使用index_sequence 作为zero_sequence 的模板参数时,实现的特化匹配并被选中。

但是当您使用从index_sequence 继承的make_index_sequence 并且可以转换为index_sequence 但不完全是index_sequence 时,专业化与通用(未实现)版本不匹配的zero_sequence 被选中。

通过一个函数,我建议的zeHelper() 或类似的东西,可以避免这个问题,因为make_index_sequence 可以转换为index_sequence

【讨论】:

    猜你喜欢
    • 2015-12-24
    • 2011-02-17
    • 1970-01-01
    • 2022-01-09
    • 2022-12-04
    • 2015-05-12
    • 2023-01-04
    • 1970-01-01
    相关资源
    最近更新 更多