Q:

Why isn't this constexpr in a variadic function template constant?

In my class (which is a variadic class template), I need a constexpr for the sizeof() of the largest type passed in a variadic template. Like this:
template<class... Types>
class DiscriminatedUnion
{
.
.
.
static constexpr auto value = maxSizeOf<Types...>();

The code I have come up with for maxSizeOf() is the following:
template <class T>
static constexpr T static_max(T a, T b) {
    return a < b ? b : a;
}

template <class T, class... Ts>
static constexpr T static_max(T a, Ts... bs) {
    return static_max(a, static_max(bs...));
}

template <class T>
static constexpr int maxSizeOf() {
    return sizeof(T);
};

template <class T, class... Ts>
static constexpr int maxSizeOf() {
    return static_max(sizeof(T), maxSizeOf<Ts...>());
};

But in Visual Studio 2017, I am getting a compile error "expression did not evaluate to a constant."
I am not sure what it is that is not allowing the expression to be constant. I've tried compiling different things to ensure that they can be constant. I've tried using a sizeof() with a template parameter in a constexpr function, which works, which I expect since the size of types is always known at compile time. Integer arithmetic and comparison seems to be valid in a constexpr function, but I tried some again for verification. Then I've tried using integer arithmetic in the variadic template method, without sizeof(), with the following:
template <class T>
static constexpr int maxSizeOf(int n) {
    return n;
};

template <class T, class... Ts>
static constexpr int maxSizeOf(int n) {
    return static_max(n, maxSizeOf<Ts...>(n + 1));
};

static constexpr int numBytes = maxSizeOf<Types...>(1);

And this does not work. So I'm thinking it must be something to do with the variadic method template expansion. But this should be able to be made a compile-time constant, because variadic template packs are always expanded at compile time. Does anyone know why these can't be constexpr?

A:

"expression did not evaluate to a constant." seems not the root cause. Your static_max and maxSizeOf need modifications to make the compiler happy. You can refer to this post to see how to do that under different C++ standards.
For example :
template <class T, class... Ts>
static constexpr T static_max(T a, Ts... bs) {
    if constexpr (sizeof...(Ts) == 0)
        return a;
    else
        return std::max(a, static_max(bs...));
}

template <class T, class... Ts>
static constexpr int maxSizeOf(int n) {
    if constexpr (sizeof...(Ts) == 0)
        return n;
    else
        return static_max(n, maxSizeOf<Ts...>(n + 1));
};

Actually, we don't need static_max at all. All we need here is to find the max within just 2 values, and std::max is already there.
EDIT: it seems that we don't need maxSizeOf either... as Nathan mentioned in the comments, std::max can deal with initializer_list as well.

