2

Is there a way to construct a template class that functions as both a compile and runtime array (much like the C89 constant size array and the same C99 variable length array) which allows for logical semantics (one template parameter for the variable length array, two for the fixed length, much like std::array).

To top it off, I'd like to prevent code duplication between the two cases, as most functions are identical between the two cases. Is there a way to use constexpr or enable_if to achieve this?

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • IIUC, you want a statically allocated `std::vector` that can store a variable number of elements, but with a compile time limit for its maximum size? – Didier Trosset Jan 05 '12 at 12:15

2 Answers2

5

The Eigen linear algebra library did this exact thing, with C++03 only. Their matrices have compile-time sizes with a special value (Eigen::Dynamic) indicating that the size should be chosen at runtime. Through template specialization, the storage is realized.

Example:

template <typename Type,int N>
class Array {
   Type data[N];
};

template <typename Type>
class Array<Type,Dynamic> {
   boost::scoped_array<Type> data;
};
thiton
  • 35,651
  • 4
  • 70
  • 100
  • You don't need template specialization, that would just create unnecessary code duplication. – Šimon Tóth Jan 05 '12 at 12:15
  • 1
    @Let_Me_Be: Specialize only the storage, and you have very little duplication. The key insight is that the array operations are independent of the storage model. – thiton Jan 05 '12 at 12:19
  • Still it is one extra level of unneeded indirection. – Šimon Tóth Jan 05 '12 at 12:20
  • @Let_Me_Be: The Eigen library gets excellent mileage from this indirection. – thiton Jan 05 '12 at 12:23
  • Yeah, yeah, the Eigen developers are geniuses. I get it. Again, the indirection is unnecessary and just creates code duplication. That doesn't mean that this solution won't work, it's just unnecessary complex. – Šimon Tóth Jan 05 '12 at 12:25
  • This specialization is the kind of code duplication I want to avoid. Is there no other trick possible using perhaps newer C++11 features or SFINAE? – rubenvb Jan 05 '12 at 12:56
  • @Let_Me_Be : What "indirection" are you even talking about? I see none here. – ildjarn Jan 05 '12 at 18:51
  • @iljarn Of course you don't see any indirection. This code is the extra indirection level that isn't needed. – Šimon Tóth Jan 05 '12 at 19:00
  • @Let_Me_Be : "*it is one extra level of unneeded indirection*", "*the indirection is unnecessary*", "*Of course you don't see any indirection*" -- uh, okay. – ildjarn Jan 05 '12 at 19:36
  • 1
    @rubenvb: You say this is the type of duplication you want to avoid. thiton has already mentioned that you should only use this for the storage. Are you still thinking you need to duplicate the access to the storage? Or do you have some other duplication concern? Because you don't need any more duplication than this - which is the minimal you need to specify two different types. You just use a traits class and in your class to define the type as above. Then in your class you use `StorageTraits::type data;` to define your member data. Or c++11's templated aliases... – ex0du5 Jan 06 '12 at 21:21
1

Yes, no problem. Have the size parameter with a default value -1, and just make a static if (type chooser) in the class to choose a static array, or a dynamic array.

The internal logic should be most identical, different parts can be easily resolved using overloading.

The usage then would be:

array<int> x; /* dynamic array */
array<int,10> y; /* static array */
Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
  • What do you mean by `static if` exactly? A real `if` statement in the constructor? – rubenvb Jan 05 '12 at 12:47
  • @rubenvb Just to select between the two types. You can use `enable_if` from boost, or just use type selector like this one: http://stackoverflow.com/a/1037357/211659 – Šimon Tóth Jan 05 '12 at 13:13