我一直在尝试编写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 I think I got it from here中使用index_sequencemake_index_sequence的以下实现:
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> {};

最佳答案

我建议zero_sequence完全不同:不是struct,而是基于usingdecltype()和仅声明的辅助函数的std::declval()(在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的模板参数时,已实现的专业匹配并被选择。

但是,当您使用make_index_sequence时,它继承自index_sequence并可以转换为index_sequence但不完全是index_sequence,因此特殊性不匹配,并且选择了zero_sequence的通用(未实现)版本。

通过函数,我建议的zeHelper()或类似的方法避免了此问题,因为make_index_sequence可转换为index_sequence

08-16 00:58