1

I'm complementing a python-like range class (let's call it Range). I'd like to use std::array to store data if the argument is constexpr, and std::vector otherwise.

I wonder if I can use the same interface to do it, that is ,
Range range_1(10); stores data in std::array, and int n=5; Range range_2(n); stores data in std::vector

I found this, which can judge if a function is constexpr. But it is unclear to me how to migrate it to a variable. Can someone help me?

  • 1
    arrays and vectors aside, the equivalent of python's range is c++ [std::ranges:iota](https://en.cppreference.com/w/cpp/ranges/iota_view), python `range` doesn't store the data in a list, instead it is a generator, the c++ equivalent is also a generator (called ranges in c++) – Ahmed AEK Aug 26 '23 at 12:10

1 Answers1

0

std::array requires compile time constant, function arguments are not constexpr even in constant expression.

So not possible with exactly your interface.

If you agree with Range range_1(std::integral_constant<std::size_t, 10>{}); instead, you might do:

template <std::size_t N>
using IC = std::integral_constant<std::size_t, N>; 
// Possibly create udl with operator ""_ic to have 42_ic syntax

constexpr std::size_t dynamic_extent = -1;

template <std::size_t N>
struct Range
{
    Range(IC<N>) {}

    std::array<int, N> data{};
};

template <>
struct Range<dynamic_extent>
{
    Range(std::size_t N) : data(N) {}

    std::vector<int> data;
};

// CTAD
template <std::size_t N> Range(IC<N>) -> Range<N>;
Range(std::size_t) -> Range<dynamic_extent>;

// Testing
Range r1(IC<10>{});
Range r2(10);

static_assert(std::is_same_v<decltype(r1.data), std::array<int, 10>>);
static_assert(std::is_same_v<decltype(r2.data), std::vector<int>>);

Demo

Notice than CTAD is a all or nothing, so if you attend to have Range<T, N>, it would not be directly possible.

Jarod42
  • 203,559
  • 14
  • 181
  • 302