Grzegorz Głowacki
Grzegorz Głowacki

Reputation: 193

Enum is not a constexpr?

I have such a source code, there is an enumeration which i hope could be evaluated as constexpr, but compiler gives me an error, that it isn't. Why? It doesn't matter if EventOrder is an enum or enum class.

#include <limits>
#include <type_traits>

enum class EventOrder
{
        Last = 1'000'000,
        Default = 0,
        Logger = -1024,
        First = -1'000'000
};

template <typename T>
constexpr inline std::underlying_type_t<T> num(T value) {
        static_assert(std::is_enum<T>::value, "num can only be used on enumeration types");
        return static_cast<std::underlying_type_t<T>>(value);
}

constexpr EventOrder sum(const EventOrder order, const std::underlying_type_t<EventOrder> orderDelta)
{
        static_assert(order >= EventOrder::First, "Order Value out of bounds");
        return static_cast<EventOrder>(num(order) + orderDelta);
}

int main( )
{
        constexpr EventOrder e = EventOrder::Default;
        sum(e, 2);
        return 0;
}

It gives error:

    $ g++ -std=c++14 EventTest.cc
EventTest.cc: In function ‘constexpr EventOrder sum(EventOrder, std::underlying_type_t<EventOrder>)’:
EventTest.cc:23:2: error: non-constant condition for static assertion
  static_assert(order >= EventOrder::First, "Order Value out of bounds");
  ^
EventTest.cc:23:2: error: ‘order’ is not a constant expression  

Why order is not a constexpr?

Edit 1

So is passing arguments as template variables only way to solve that? Or You know some different way?

#include <limits>
#include <type_traits>

enum class EventOrder
{
        Last = 1'000'000,
        Default = 0,
        Logger = -1024,
        First = -1'000'000
};

template <typename T> constexpr inline std::underlying_type_t<T> num(T value)
{
    static_assert(std::is_enum<T>::value, "num can only be used on enumeration types");
    return static_cast<std::underlying_type_t<T>>(value);
}

template< typename T >
constexpr bool LimitedValue(const T value, const T min, const T max)
{
        return value >= min && value <= max;
}

template <EventOrder orderl, std::underlying_type_t<EventOrder> orderr>
constexpr std::underlying_type_t<EventOrder>  orderSum()
{
        return num(orderl) + orderr;
}

template <EventOrder orderl, std::underlying_type_t<EventOrder> orderr>
constexpr EventOrder order()
{
        static_assert(LimitedValue(orderSum<orderl, orderr>(), num(EventOrder::First), num(EventOrder::Last)), "order out of baunds");
        return static_cast<EventOrder>(orderSum<orderl, orderr>());
}

int main()
{
        EventOrder e = order<EventOrder::Default, 2>();

}

Upvotes: 4

Views: 4100

Answers (1)

R Sahu
R Sahu

Reputation: 206567

Even though the function is a constexpr function, it can still be called with a non-const argument. Hence, when the compiler processes the function, it cannot know the value of order and cannot be use it in a static_assert.

Upvotes: 2

Related Questions