Создание index_sequence N нулей - PullRequest
0 голосов
/ 07 сентября 2018

Я пытался написать тип 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).

В случае, если это имеет отношение к объяснению этого поведения, я использую следующую реализацию index_sequence и make_index_sequence в C ++ 11 Я думаю, что получил ее отсюда :

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

1 Ответ

0 голосов
/ 07 сентября 2018

Я предлагаю zero_sequence совершенно другое: не struct, а using на основе decltype(), 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>()));

и вы можете отклонить a0 и b0

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.

...