0

I understand that a strongly typed enumerator can be converted to its underlying type as:

template<typename E> constexpr 
auto to_integral(E e) -> typename std::underlying_type<E>::type
{
    return static_cast<typename std::underlying_type<E>::type>(e);
}

However, this is working in run-time.

Since enumerators are there already in compilation time, is there a way to do such conversion during compilation time?

athos
  • 6,120
  • 5
  • 51
  • 95
  • 3
    "However, this is working in run-time." Why do you think so? – cpplearner Aug 08 '18 at 01:40
  • @cpplearner it's a function call, function calls work in run-time, right? – athos Aug 08 '18 at 01:41
  • It is true that "function calls work in run-time", however `constexpr` functions are a little bit ***special*** in that regard. To make a long story short, if all parameters to a `constexpr` functions are compile-time constants, then, subject to certain restrictions, the function gets evaluated at a compile time. – Sam Varshavchik Aug 08 '18 at 01:56
  • @SamVarshavchik if i'm not wrong, `constexpr` is not *guaranteed* to work in compilation time, that depends on compiler, right? – athos Aug 08 '18 at 01:58
  • 2
    The standard doesn't have this notion of "compilation time" at all, so it cannot guarantee anything about it. It has a notion of "constant expression" instead. – n. m. could be an AI Aug 08 '18 at 02:06
  • @n.m. macros, template programming, etc are guaranteed to be in compilation time, though it's not explicitly stated, right? – athos Aug 08 '18 at 02:08
  • The standard doesn't mandate that there *is* compilation time, or indeed even such a thing as compiler, neither explicitly nor implicitly. – n. m. could be an AI Aug 08 '18 at 02:12
  • @n.m. i see, thx. – athos Aug 08 '18 at 02:20
  • 4
    IMO if the compiler doesn't optimize that call away *completely* it won't optimize anything. – Galik Aug 08 '18 at 02:30
  • By definition, `constexpr` is evaluated at compile-time, not runtime. So is `static_cast`. – Remy Lebeau Aug 08 '18 at 05:09
  • @RemyLebeau I doubt. Static_cast can work on a variable – athos Aug 08 '18 at 05:10
  • 1
    I played with your sample on godbolt. For this, I added a 2nd `to_integral_rt()` without `constexpr` (to see the difference). gcc 8.1 `--std=c++17` compiles one `mov` for `const int i = to_integral(E::E123);`, and `mov` `call to_integral_rt()` `mov` for the non-`constexpr` flavor. However, adding `-O2` both calls are optimized away - Both constants are directly set into output commands. (I expected that as I did fiddle with similar things in the past.) [**Live Demo on godbolt**](https://godbolt.org/g/c19t52) – Scheff's Cat Aug 08 '18 at 06:02
  • @athos `static_cast` is evaluated at compile-time, even though it can be applied to a variable known only at runtime. The cast is validated by the compiler for legality and then compiled to static machine code that is applied to the variable at runtime. – Remy Lebeau Aug 08 '18 at 07:46

2 Answers2

2

As herb sutter mentioned in the below link,

When does a constexpr function get evaluated at compile time?

constexpr functions will be evaluated at compile time when all its arguments are constant expressions and the result is used in a constant expression as well. A constant expression could be a literal (like 42), a non-type template argument (like N in template class array;), an enum element declaration (like Blue in enum Color { Red, Blue, Green };, another variable declared constexpr, and so on.

They might be evaluated when all its arguments are constant expressions and the result is not used in a constant expression, but that is up to the implementation.

cpp_enthusiast
  • 1,239
  • 10
  • 28
1

The function you wrote is OK to be used at compile time.

template<typename E> constexpr 
auto to_integral(E e) -> typename std::underlying_type<E>::type
{
    return static_cast<typename> std::underlying_type<E>::type>(e);
}

enum class A : int { a };
static_assert(to_integral(A::a) == 0);

This should compile, indicating that the function can be ran at compile time. However, constexpr functions only indicate that the function complies with all requirements to be executed at compile time. To enforce this being calculated (even at -O0), you need to make your variables also constexpr.

 constexpr auto i = to_integral(A::a);
 i = 42;

For a variable, the constexpr simply means: initialize at compile time. Afterwards, you can use it as if it was runtime.

In the example above, I'm convinced that most compilers will optimize the code regardless of the constexpr keyword. (Given -O2 or -O3) However if the code becomes more complex the constexpr is required to force them to optimize it, regardless of the cost.

JVApen
  • 11,008
  • 5
  • 31
  • 67