Skip to content

Comment on A nice, little known C feature: Static array indices in parameter declarations

Comments

In C++, you can do this by passing the array by reference:

    void foo(int (&foo)[10]) {}
However, that is not "minimum of 10" but "exactly 10".

You can also get the size at compile time:

    template <size_t N> void foo(int (&foo)[N]) { int newarry[N+2]; }
I've used the above for something like this:
    template <size_t N> void safe_strcpy(char (&buf)[N], const char *src) { 
      strncpy(buf, src, N-1); 
      buf[N-1] = 0; 
    }

And, by extending your second example, we can enforce the minimum array size with std::enable_if (C++11; boost::enable_if_c with C++03):

    template <size_t N>
    typename enable_if<(N >= 10), void>::type
    foo(int (&bar)[N]) { ... }
EDIT: Changed condition from N >= 0 into a more meaningful one. X-)

... and just as I was going to make a smart-ass joke about Boost probably having another contrived contraption just for that - there it is, already sneaked into the standard too.

The more readable C++11 version would use static_assert:

    template <size_t N>
    foo(int (&bar)[N]) 
    { 
        static_assert(N >= 10, "Array needs >= 10 elements!"); 
        ...
    }

Correct. The key difference is that the enable_if version can be overloaded with mutually exclusive requirements:

    template <size_t N>
    typename enable_if<(1 < N && N < 10), void>::type
    foo(int (&bar)[N])
    {
        // called when 1 < N && N < 10
    }

    template <size_t N>
    typename enable_if<(N >= 10), void>::type
    foo(int (&bar)[N])
    {
        // called when N >= 10
    }
OTOH, the key advantage in static_assert is the meaningful error message.

This will generate separate function bodies for different values of N.

I don't think that is more readable. With enable_if the precondition is clearly visible at the function header, while the static_assert is inside the body and thus more easily accidentally ignored.

On the other hand, static_assert will have a more helpful compile error for users of the code. They will clearly see assertion condition that failed, rather than missing candidate error due to substitution failure (or worse, a different overload silently considered instead).

This works with pointers in both C and C++. int (*foo)[10] is a pointer to an array of exactly 10 elements. The novel thing being pointed out in the OP is the "10 or more" aspect.

That's true, until you forget and type foo[i] instead of (* foo)[i]. Of course, compilers will usually catch that mistake at compile time...

There'a an interesting analogy with structs here. K&R invented the -> operator specifically to obviate (* ptr).member. It's too bad that arrays took a different route through C's history and didn't manage to end up in a place where a similar convenience would make sense.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.