Skip to main content
Code Review

Return to Answer

replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link
  • In C++, ranges tend to be [begin, end) ranges. Your compile-time integer ranges are actually [begin, end] ranges. The last element should not be included in the range. Therefore, you change this code:

     template<int S, int E>
     struct Range: GetRange<E-S+1, S>
     {};
    

    By this one:

     template<int S, int E>
     struct Range: GetRange<E-S, S>
     {};
    

    I tried it and it even works for Range<8,8> by producing an empty range.

  • Currently, your Range only works for increasing ranges of values (and empty ones). You could modify your code so that it also works with decreasing ranges of values. What I did is probably not really clean, but it works (take it as a proof of concept). I replaced Range and GetRange by the following classes:

     template<int C, int P, int... N>
     struct GetIncreasingRange:
     GetIncreasingRange<C-1, P+1, N..., P>
     {};
     template<int C, int P, int... N>
     struct GetDecreasingRange:
     GetDecreasingRange<C+1, P-1, N..., P>
     {};
     template<int P, int... N>
     struct GetIncreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int P, int... N>
     struct GetDecreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int S, int E, bool Increasing=(S<E)>
     struct Range;
     template<int S, int E>
     struct Range<S, E, true>:
     GetIncreasingRange<E-S, S>
     {};
     template<int S, int E>
     struct Range<S, E, false>:
     GetDecreasingRange<E-S, S>
     {};
    

    These ranges are [begin, end) ranges and also work for empty ranges.

  • Another possible improvement would be to let the user choose the integer type he wants to use for his range. That is actually what is done in the C++14 class std::integer_sequence, provided along with std::index_sequence which is its specialization for a range of std::size_t values. Here Here is a possible implementation.

  • Also, in your function call, you can drop the std::vector and replace it by std::array. The number of values is known at compile time (thanks to the operator sizeof...), so there's no need to use a dynamic storage container.

     static void call()
     {
     std::array<int, sizeof...(N)> v { N... };
     std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, "\n"));
     }
    
  • In C++, ranges tend to be [begin, end) ranges. Your compile-time integer ranges are actually [begin, end] ranges. The last element should not be included in the range. Therefore, you change this code:

     template<int S, int E>
     struct Range: GetRange<E-S+1, S>
     {};
    

    By this one:

     template<int S, int E>
     struct Range: GetRange<E-S, S>
     {};
    

    I tried it and it even works for Range<8,8> by producing an empty range.

  • Currently, your Range only works for increasing ranges of values (and empty ones). You could modify your code so that it also works with decreasing ranges of values. What I did is probably not really clean, but it works (take it as a proof of concept). I replaced Range and GetRange by the following classes:

     template<int C, int P, int... N>
     struct GetIncreasingRange:
     GetIncreasingRange<C-1, P+1, N..., P>
     {};
     template<int C, int P, int... N>
     struct GetDecreasingRange:
     GetDecreasingRange<C+1, P-1, N..., P>
     {};
     template<int P, int... N>
     struct GetIncreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int P, int... N>
     struct GetDecreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int S, int E, bool Increasing=(S<E)>
     struct Range;
     template<int S, int E>
     struct Range<S, E, true>:
     GetIncreasingRange<E-S, S>
     {};
     template<int S, int E>
     struct Range<S, E, false>:
     GetDecreasingRange<E-S, S>
     {};
    

    These ranges are [begin, end) ranges and also work for empty ranges.

  • Another possible improvement would be to let the user choose the integer type he wants to use for his range. That is actually what is done in the C++14 class std::integer_sequence, provided along with std::index_sequence which is its specialization for a range of std::size_t values. Here is a possible implementation.

  • Also, in your function call, you can drop the std::vector and replace it by std::array. The number of values is known at compile time (thanks to the operator sizeof...), so there's no need to use a dynamic storage container.

     static void call()
     {
     std::array<int, sizeof...(N)> v { N... };
     std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, "\n"));
     }
    
  • In C++, ranges tend to be [begin, end) ranges. Your compile-time integer ranges are actually [begin, end] ranges. The last element should not be included in the range. Therefore, you change this code:

     template<int S, int E>
     struct Range: GetRange<E-S+1, S>
     {};
    

    By this one:

     template<int S, int E>
     struct Range: GetRange<E-S, S>
     {};
    

    I tried it and it even works for Range<8,8> by producing an empty range.

  • Currently, your Range only works for increasing ranges of values (and empty ones). You could modify your code so that it also works with decreasing ranges of values. What I did is probably not really clean, but it works (take it as a proof of concept). I replaced Range and GetRange by the following classes:

     template<int C, int P, int... N>
     struct GetIncreasingRange:
     GetIncreasingRange<C-1, P+1, N..., P>
     {};
     template<int C, int P, int... N>
     struct GetDecreasingRange:
     GetDecreasingRange<C+1, P-1, N..., P>
     {};
     template<int P, int... N>
     struct GetIncreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int P, int... N>
     struct GetDecreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int S, int E, bool Increasing=(S<E)>
     struct Range;
     template<int S, int E>
     struct Range<S, E, true>:
     GetIncreasingRange<E-S, S>
     {};
     template<int S, int E>
     struct Range<S, E, false>:
     GetDecreasingRange<E-S, S>
     {};
    

    These ranges are [begin, end) ranges and also work for empty ranges.

  • Another possible improvement would be to let the user choose the integer type he wants to use for his range. That is actually what is done in the C++14 class std::integer_sequence, provided along with std::index_sequence which is its specialization for a range of std::size_t values. Here is a possible implementation.

  • Also, in your function call, you can drop the std::vector and replace it by std::array. The number of values is known at compile time (thanks to the operator sizeof...), so there's no need to use a dynamic storage container.

     static void call()
     {
     std::array<int, sizeof...(N)> v { N... };
     std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, "\n"));
     }
    
Added links to improve the answer.
Source Link
Morwenn
  • 20.2k
  • 3
  • 69
  • 132
  • In C++, ranges tend to be [begin, end) ranges. Your compile-time integer ranges are actually [begin, end] ranges. The last element should not be included in the range. Therefore, you change this code:

     template<int S, int E>
     struct Range: GetRange<E-S+1, S>
     {};
    

    By this one:

     template<int S, int E>
     struct Range: GetRange<E-S, S>
     {};
    

    I tried it and it even works for Range<8,8> by producing an empty range.

  • Currently, your Range only works for increasing ranges of values (and empty ones). You could modify your code so that it also works with decreasing ranges of values. What I did is probably not really clean, but it works (take it as a proof of concept). I replaced Range and GetRange by the following classes:

     template<int C, int P, int... N>
     struct GetIncreasingRange:
     GetIncreasingRange<C-1, P+1, N..., P>
     {};
     template<int C, int P, int... N>
     struct GetDecreasingRange:
     GetDecreasingRange<C+1, P-1, N..., P>
     {};
     template<int P, int... N>
     struct GetIncreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int P, int... N>
     struct GetDecreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int S, int E, bool Increasing=(S<E)>
     struct Range;
     template<int S, int E>
     struct Range<S, E, true>:
     GetIncreasingRange<E-S, S>
     {};
     template<int S, int E>
     struct Range<S, E, false>:
     GetDecreasingRange<E-S, S>
     {};
    

    These ranges are [begin, end) ranges and also work for empty ranges.

  • Another possible improvement would be to let the user choose the integer type he wants to use for his range. That is actually what is done in the C++14 class std::integer_sequencestd::integer_sequence, provided along with std::index_sequence which is its specialization for a range of std::size_t values. Here is a possible implementation.

  • Also, in your function call, you can drop the std::vector and replace it by std::array. The number of values is known at compile time (thanks to the operator sizeof...), so there's no need to use a dynamic storage container.

     static void call()
     {
     std::array<int, sizeof...(N)> v { N... };
     std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, "\n"));
     }
    
  • In C++, ranges tend to be [begin, end) ranges. Your compile-time integer ranges are actually [begin, end] ranges. The last element should not be included in the range. Therefore, you change this code:

     template<int S, int E>
     struct Range: GetRange<E-S+1, S>
     {};
    

    By this one:

     template<int S, int E>
     struct Range: GetRange<E-S, S>
     {};
    

    I tried it and it even works for Range<8,8> by producing an empty range.

  • Currently, your Range only works for increasing ranges of values (and empty ones). You could modify your code so that it also works with decreasing ranges of values. What I did is probably not really clean, but it works (take it as a proof of concept). I replaced Range and GetRange by the following classes:

     template<int C, int P, int... N>
     struct GetIncreasingRange:
     GetIncreasingRange<C-1, P+1, N..., P>
     {};
     template<int C, int P, int... N>
     struct GetDecreasingRange:
     GetDecreasingRange<C+1, P-1, N..., P>
     {};
     template<int P, int... N>
     struct GetIncreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int P, int... N>
     struct GetDecreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int S, int E, bool Increasing=(S<E)>
     struct Range;
     template<int S, int E>
     struct Range<S, E, true>:
     GetIncreasingRange<E-S, S>
     {};
     template<int S, int E>
     struct Range<S, E, false>:
     GetDecreasingRange<E-S, S>
     {};
    

    These ranges are [begin, end) ranges and also work for empty ranges.

  • Another possible improvement would be to let the user choose the integer type he wants to use for his range. That is actually what is done in the C++14 class std::integer_sequence, provided along with std::index_sequence which is its specialization for a range of std::size_t values.

  • Also, in your function call, you can drop the std::vector and replace it by std::array. The number of values is known at compile time (thanks to the operator sizeof...), so there's no need to use a dynamic storage container.

     static void call()
     {
     std::array<int, sizeof...(N)> v { N... };
     std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, "\n"));
     }
    
  • In C++, ranges tend to be [begin, end) ranges. Your compile-time integer ranges are actually [begin, end] ranges. The last element should not be included in the range. Therefore, you change this code:

     template<int S, int E>
     struct Range: GetRange<E-S+1, S>
     {};
    

    By this one:

     template<int S, int E>
     struct Range: GetRange<E-S, S>
     {};
    

    I tried it and it even works for Range<8,8> by producing an empty range.

  • Currently, your Range only works for increasing ranges of values (and empty ones). You could modify your code so that it also works with decreasing ranges of values. What I did is probably not really clean, but it works (take it as a proof of concept). I replaced Range and GetRange by the following classes:

     template<int C, int P, int... N>
     struct GetIncreasingRange:
     GetIncreasingRange<C-1, P+1, N..., P>
     {};
     template<int C, int P, int... N>
     struct GetDecreasingRange:
     GetDecreasingRange<C+1, P-1, N..., P>
     {};
     template<int P, int... N>
     struct GetIncreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int P, int... N>
     struct GetDecreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int S, int E, bool Increasing=(S<E)>
     struct Range;
     template<int S, int E>
     struct Range<S, E, true>:
     GetIncreasingRange<E-S, S>
     {};
     template<int S, int E>
     struct Range<S, E, false>:
     GetDecreasingRange<E-S, S>
     {};
    

    These ranges are [begin, end) ranges and also work for empty ranges.

  • Another possible improvement would be to let the user choose the integer type he wants to use for his range. That is actually what is done in the C++14 class std::integer_sequence, provided along with std::index_sequence which is its specialization for a range of std::size_t values. Here is a possible implementation.

  • Also, in your function call, you can drop the std::vector and replace it by std::array. The number of values is known at compile time (thanks to the operator sizeof...), so there's no need to use a dynamic storage container.

     static void call()
     {
     std::array<int, sizeof...(N)> v { N... };
     std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, "\n"));
     }
    
Source Link
Morwenn
  • 20.2k
  • 3
  • 69
  • 132

Generally speaking, it's good and works great (version 2 seems better). There are some things that could be changed/added though:

  • In C++, ranges tend to be [begin, end) ranges. Your compile-time integer ranges are actually [begin, end] ranges. The last element should not be included in the range. Therefore, you change this code:

     template<int S, int E>
     struct Range: GetRange<E-S+1, S>
     {};
    

    By this one:

     template<int S, int E>
     struct Range: GetRange<E-S, S>
     {};
    

    I tried it and it even works for Range<8,8> by producing an empty range.

  • Currently, your Range only works for increasing ranges of values (and empty ones). You could modify your code so that it also works with decreasing ranges of values. What I did is probably not really clean, but it works (take it as a proof of concept). I replaced Range and GetRange by the following classes:

     template<int C, int P, int... N>
     struct GetIncreasingRange:
     GetIncreasingRange<C-1, P+1, N..., P>
     {};
     template<int C, int P, int... N>
     struct GetDecreasingRange:
     GetDecreasingRange<C+1, P-1, N..., P>
     {};
     template<int P, int... N>
     struct GetIncreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int P, int... N>
     struct GetDecreasingRange<0, P, N...>:
     Sizes<N...>
     {};
     template<int S, int E, bool Increasing=(S<E)>
     struct Range;
     template<int S, int E>
     struct Range<S, E, true>:
     GetIncreasingRange<E-S, S>
     {};
     template<int S, int E>
     struct Range<S, E, false>:
     GetDecreasingRange<E-S, S>
     {};
    

    These ranges are [begin, end) ranges and also work for empty ranges.

  • Another possible improvement would be to let the user choose the integer type he wants to use for his range. That is actually what is done in the C++14 class std::integer_sequence, provided along with std::index_sequence which is its specialization for a range of std::size_t values.

  • Also, in your function call, you can drop the std::vector and replace it by std::array. The number of values is known at compile time (thanks to the operator sizeof...), so there's no need to use a dynamic storage container.

     static void call()
     {
     std::array<int, sizeof...(N)> v { N... };
     std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, "\n"));
     }
    
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /