tags:

views:

204

answers:

5

Is there anyway to restrict the size of an array when passed as an argument to a function?

I mean is something like this possible?

/*following will lead to compile time error */

template<typename T, size_t n>=20> // or template<typename T,size_t n<=20>
void func(T (&a)[n])
{
   // do something with a

}

I want the size of my array to be at least(or at most) n(n can have any value).

For example:

When n=20 I must pass an array with at least(or at most) 20 elements. Is there any way in C++ for this?

+15  A: 

You can simply make the requirement a static assertion - e.g. with Boosts static assert:

template<typename T, size_t n> 
void func(T (&a)[n]) {
    BOOST_STATIC_ASSERT(n >= 20);
    // ...
}

A basic custom implementation (not solving the problem of using it more then once per scope) might look like the following:

template<bool b> struct StaticAssert;
template<> struct StaticAssert<true> {};
#define STATIC_ASSERT(x) StaticAssert<(x)> static_asserter 

If you want different behaviour if the requirement is met, use something like enable_if or tag-based specialization. Example using enable_if:

template<class T, size_t n>
typename boost::enable_if<(n >= 20), void>::type
func(T (&a)[n]) { /* ... */ }

template<class T, size_t n>
typename boost::disable_if<(n >= 20), void>::type
func(T (&a)[n]) { /* ... */ }
Georg Fritzsche
Note: Knowing the size does not prevent you from accessing beyond the end (ie the compiler will not check your array indexes).
Martin York
+ 1 very intersting: didn't know about this macro, that allows to receive a compile time error.
sergiom
the C++ template mechanism kicks arse ! if you find this interesting get the books from my answer. :D
Hassan Syed
@martin (+1) you are sort-of right; however it is trivial to hard-code the `size_t n` as a const to provide bounds checking at runtime. Also if boost::mpl is used and the indices are known at compile time, then it is also possible to do compile-time bounds checking :D
Hassan Syed
This boost macro certainly seems to be handling the arrays for which size is known at compile time. However it may not work with dynamically allocated arrays.
hype
Georg Fritzsche
@gf: Thanks for your response. BTW is there any way without using boost library?
Prasoon Saurav
@prasoon copy out the code you need from boost. Or get the book I have suggested and write the functionality yourself. In either case the functionality is quite succinct.
Hassan Syed
@Prasoon: added simple example. Extracting components from boost can be done with bcp by the way. For an introduction into the whole area *Modern C++ design* that Hassan mentioned is great.
Georg Fritzsche
@Hassan and @gf: Thanks for the info. I have already started reading Modern C++ design . The book is certainly very good and very highly recommended. :-)
Prasoon Saurav
A: 

You are trying to use templates (compile time) to know how many items will be in your array at runtime. It is not possible to do like you try to do it.

You will have to rely on code outside your function or inside the function

Eric
ofcourse it is, the template mechanism in C++ is turing complete.
Hassan Syed
Arrays in the strict sense have their size fixed at compile-time.
visitor
A: 

There isn't such a construct in C++, that allows you to receive a compile time error. But I think that using templates you could implement a framework containing something like a LimitedArray class to be used instead of a basic array type.

sergiom
+5  A: 

GF's answer is correct, if you want more features or decisions points at compile time, you might want to look at boost::mpl. C++ Template Metaprogramming outlines what is possible with boost::MPL and how it was designed. Modern C++ design, which is not related to MPL, goes into design techniques which leverage compile time polymorphism

Hassan Syed
I thought that one shouldn't have to follow the links to see what books the refer to, just change it if it doesn't suit you.
Georg Fritzsche
thanks gf, I was being lazy :P
Hassan Syed
+3  A: 

GF's answer is pretty cool, but Boost.Array can't go without mention.

template< typename T >
void func( boost::array< T, 20 > &a ) {

Given your question and GF's answer, it looks like a computationally free, type- and range-safe implicit conversion from T(&)[20] to some_array_template<T,20> would be semantically possible, but boost::array doesn't allow that. Still, you might consider moving entirely to boost::array if you have lots of similar logic. And it's simple enough to use as a basis to roll your own, if you do want implicit conversion.

Potatoswatter