сила constexpr 10 нерекурсивным способом? - PullRequest
0 голосов
/ 25 июня 2018

Очень просто реализовать constexpr мощность 10 рекурсивным способом:

template<int exp, bool = (exp > 0)>
struct pow10 {
    static constexpr double value = pow10<exp - 1>::value * 10.0;
};

template<>
struct pow10<0, false> {
    static constexpr double value = 1.0;
};

template<int exp>
struct pow10<exp, false> {
    static constexpr double value = pow10<exp + 1>::value / 10.0;
};

template<int exp>
static constexpr double pow10_v = pow10<exp>::value;

static_assert(pow10_v<-3> == 1e-3, "");
static_assert(pow10_v<2> == 1e2, "");

Можно ли сделать constexpr мощность 10 нерекурсивным способом?

К вашему сведению, я использую VS2015, который не поддерживает relaxed- constexpr в C ++ 14, поэтому я не могу использовать цикл for в функции constexpr.

1 Ответ

0 голосов
/ 25 июня 2018

Итак, если я правильно понимаю, вы компилируете C ++ 14, но ваш компилятор не полностью совместим с функциями C ++ 14 constexpr.Так что вы не можете сделать цикл внутри constexpr функции.

Ну ... у меня нет вашего компилятора, поэтому я не знаю, что именно ваш компилятор не поддерживает, поэтому я предлагаюрешение C ++ 14, основанное на нерекурсивной шаблонной функции constexpr variadic, которая не использует цикл for.Ну ... две функции: одна для отрицательных степеней и одна для неотрицательных степеней.

Надеемся, что VS2015 его поддержит.

Отрицательной функцией является следующий

template

constexpr T negPow10 (std::index_sequence<Is...> const &)
 {
   using unused = std::size_t[];

   T ret { 1 };

   (void)unused { 0U, (ret /= 10, Is)... };

   return ret;
 }

Неотрицательный (для положительных или нулевых степеней) почти равен, но используйте ret *= 10 вместо ret /= 10.

Они вызываются через следующие

template <typename T, int E, std::size_t N = (E < 0 ? -E : E)>
constexpr T pow10 ()
 { return E < 0
    ? negPow10<T>(std::make_index_sequence<N>{})
    : posPow10<T>(std::make_index_sequence<N>{}); }

Ниже приведен полный пример компиляции (но обратите внимание, что, как указывает nm, static_assert() над double power не является надежным)

#include <utility>

template <typename T, std::size_t ... Is>
constexpr T posPow10 (std::index_sequence<Is...> const &)
 {
   using unused = std::size_t[];

   T ret { 1 };

   (void)unused { 0U, (ret *= 10, Is)... };

   return ret;
 }

template <typename T, std::size_t ... Is>
constexpr T negPow10 (std::index_sequence<Is...> const &)
 {
   using unused = std::size_t[];

   T ret { 1 };

   (void)unused { 0U, (ret /= 10, Is)... };

   return ret;
 }

template <typename T, int E, std::size_t N = (E < 0 ? -E : E)>
constexpr T pow10 ()
 { return E < 0
    ? negPow10<T>(std::make_index_sequence<N>{})
    : posPow10<T>(std::make_index_sequence<N>{}); }

int main ()
 {
   static_assert( pow10<long, 5>() == 1e5, "!" );
   static_assert( pow10<double, -3>() == 1e-3, "!" );
 }

Если честно, эторешение является (или может быть) немного рекурсивным в std::make_index_sequence.

...