简体   繁体   中英

Is it possible to check if const value is known at compile time?

Currently I am rewriting/extending my C++ utility library taking new C++11 features into account. One of the new additions is a template class which gives the maximum value of a set of numbers, hopefully at compile time.

template<typename T, T... Xs> class ConstMax
{
private:
    template<typename... Ts> static constexpr T Max(Ts... xs);

    template<typename Tx> static constexpr T Max(Tx x)
    {
        return x;
    }

    template<typename T1, typename T2, typename... Ts> static constexpr T Max(T1 x, T2 y, Ts... xs)
    {
        return y > x ? Max<T2, Ts...>(y, xs...) : Max<T1, Ts...>(x, xs...);
    }

public:
    static const T Value = Max(Xs...);
};

An example use of this class:

int max = ConstMax<int, 1, 8, 66, 32, 90, 12, 33>::Value;

Here another example which might make it harder to verify if ConstMax<...>::Value was actually evaluated during compile time:

template<typename... Ts> class Variant
{
public:
    static const size_t MaxValueSize = ConstMax<size_t, sizeof(Ts)...>::Value;
};

Which results in max = 90 . I stepped trough this code using gdb and it seems there is no function call executed during the assignment of max.

My questions:

  1. Can I safely assume that ConstMax<...>::Value is always known at compile time?
  2. Is there a way to check if constexpr functions/methods are evaluated at compile time?
  3. I understand members/methods/functions defined as constexpr are not necessarily evaluated during compile time, does the fact that Value is defined as being static const change anything about this or am I better off implementing this specific case as a recursive template class?

To check if an expression is constexpr (ie, constant expression) you could use std::integral_constant type trait as follows:

#include <iostream>
#include <type_traits>

template<typename T, T... Xs> class ConstMax {
  template<typename... Ts> static constexpr T Max(Ts... xs);
  template<typename Tx> static constexpr T Max(Tx x) { return x;}
  template<typename T1, typename T2, typename... Ts>
  static constexpr T
  Max(T1 x, T2 y, Ts... xs) {
        return y > x ? Max<T2, Ts...>(y, xs...) : Max<T1, Ts...>(x, xs...);
  }
public:
    static const T Value = Max(Xs...);
};

int main() {
 std::cout << std::integral_constant<int, ConstMax<int, 1, 8, 66, 32, 90, 12, 33>::Value>::value << std::endl;   
}

Live Demo

If it's not constexpr it will break the compilation process.

  1. Can I safely assume that ConstMax<...>::Value is always known at compile time?

Yes, since it's initialized with a constant expression. But I'd modify Value to be constexpr instead of just const .

  1. Is there a way to check if constexpr functions/methods are evaluated at compile time?

Yes. Try using them in a constexpr expression. If it works, they're being evaluated at compile time. If it fails to compile, then it's not being evaluated at compile time.

  1. I understand members/methods/functions defined as constexpr are not necessarily evaluated during compile time, does the fact that Value is defined as being static const change anything about this or am I better off implementing this specific case as a recursive template class?

If you use the members in a constant expression, you're forcing them to be evaluated at compile time. So if you cared, I'd just make sure to evaluate them in constant expressions (via constexpr ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM