User defined literal arguments are not constexpr?

后端 未结 5 1058
余生分开走
余生分开走 2021-01-01 11:43

I\'m testing out user defined literals. I want to make _fac return the factorial of the number.

Having it call a constexpr function works,

相关标签:
5条回答
  • 2021-01-01 12:15

    This is how I ended up doing it:

    template <typename t>
    constexpr t pow(t base, int exp) {
      return (exp > 0) ? base * pow(base, exp-1) : 1;
    };
    
    template <char...> struct literal;
    template <> struct literal<> {
      static const unsigned int to_int = 0;
    };
    template <char c, char ...cv> struct literal<c, cv...> {
      static const unsigned int to_int = (c - '0') * pow(10, sizeof...(cv)) + literal<cv...>::to_int;
    };
    
    template <int N> struct factorial {
      static const unsigned int value = N * factorial<N - 1>::value;
    };
    template <> struct factorial<0> {
      static const unsigned int value = 1;
    };
    
    template <char ...cv>
    constexpr unsigned int operator "" _fac()
    {
      return factorial<literal<cv...>::to_int>::value;
    }
    

    Huge thanks to KerrekSB!

    0 讨论(0)
  • 2021-01-01 12:16

    I may be wrong, but I think constexpr functions can also be called with non-constant arguments (in which case they don't give a constant expression and are evaluated at runtime). Which wouldn't work well with non-type template arguments.

    0 讨论(0)
  • 2021-01-01 12:20

    @Pubby. The easy way to digest the char non-type parameter pack is to cature it into an initializer list for a string. Then you can use atoi, atof, etc:

    #include <iostream>
    
    template<char... Chars>
      int
      operator "" _suffix()
      {
        const char str[]{Chars..., '\0'};
        return atoi(str);
      }
    
    int
    main()
    {
      std::cout << 12345_suffix << std::endl;
    }
    

    Remember to tack on a null character for the C-style functions.

    0 讨论(0)
  • 2021-01-01 12:25

    In order to make use of constexpr with user defined literals, you apparently have to use a variadic template. Take a look at the second listing in the wikipedia article for an example.

    0 讨论(0)
  • 2021-01-01 12:37

    I don't know if there's a better way in C++11 to do this than the current accepted answer, but with relaxed constexpr in C++14, you can just write "normal" code:

    constexpr unsigned long long int operator "" _fac(unsigned long long int x) {
        unsigned long long int result = 1;
        for (; x >= 2; --x) {
            result *= x;
        }
        return result;
    }
    
    static_assert(5_fac == 120, "!");
    
    0 讨论(0)
提交回复
热议问题