ThreeBit
ThreeBit

Reputation: 628

constexpr template functions don't see member array sizes as const expressions

Both clang and gcc fail to compile the code below when ArrayCount is a template. This seems wrong, especially in light of the fact that the sizeof ArrayCount solution work. The template version of ArrayCount is normally a better solution, but it's getting in the way here and constexpr is seemingly not living up to the spirit of its promise.

#if 1
    template<typename T, size_t N> 
    constexpr size_t ArrayCount(T (&)[N]) 
    {
        return N;
    }
    // Results in this (clang): error : static_assert expression is not an integral constant expression
    // Results in this (gcc): error: non-constant condition for static assertion, 'this' is not a constant expression
#else
    #define ArrayCount(t) (sizeof(t) / sizeof(t[0]))
    // Succeeds
#endif

struct X
{
    int x[4];
    X() { static_assert(ArrayCount(x) == 4, "should never fail"); }
};

Upvotes: 0

Views: 273

Answers (2)

Kerrek SB
Kerrek SB

Reputation: 477388

The right solution doesn't use homebrew code, but a simple type trait:

int a[] = {1, 2, 3};

#include <type_traits>

static_assert(std::extent<decltype(a)>::value == 3, "You won't see this");

Upvotes: 2

Adam H. Peterson
Adam H. Peterson

Reputation: 4601

It makes sense to me that this code would fail to compile since ArrayCount is a function taking a non-constexpr argument. According to the standard, I believe this means that ArrayCount must be intstantiated as a non-constexpr function.

There are workarounds, of course. I can think of two off the top of my head (one implemented in terms of the other):

template<typename T> struct ArrayCount;
template<typename T, size_t N>
struct ArrayCount<T[N]> {
    static size_t const size = N;
};

template<typename T>
constexpr size_t ArrayCount2() {
    return ArrayCount<T>::size;
}

struct X {
    int x[4];
    X() {
        static_assert(ArrayCount<decltype(x)>::size == 4, "should never fail");
        static_assert(ArrayCount2<decltype(x)>() == 4, "should never fail");
    }
};

It does mean having to use decltype() when you might not wish to, but it does break the pro-forma constraint on taking a non-constexpr parameter.

Upvotes: 1

Related Questions