4

This question is being asked because of this one.

C++11 allows you to define literals like this for numeric literals:

template<char...> OutputType operator "" _suffix();

Which means that 503_suffix would become <'5','0','3'>

This is nice, although it isn't very useful in the form it's in.

How can I transform this back into a numeric type? This would turn <'5','0','3'> into a constexpr 503. Additionally, it must also work on floating point literals. <'5','.','3> would turn into int 5 or float 5.3

A partial solution was found in the previous question, but it doesn't work on non-integers:

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;
};
// use: literal<...>::to_int
// literal<'1','.','5'>::to_int doesn't work
// literal<'1','.','5'>::to_float not implemented
Community
  • 1
  • 1
Pubby
  • 51,882
  • 13
  • 139
  • 180

2 Answers2

4

There's alwars the easy way. A non-type parameter pack can be expanded into an initializer list as follows:

#include <iostream>

template<char... Chars>
  double
  operator "" _suffix()
  {
    const char str[]{Chars..., '\0'};
    return atof(str);
  }

int
main()
{
  std::cout << 123.456789_suffix << std::endl;
}
emsr
  • 15,539
  • 6
  • 49
  • 62
3

I think the following should work on floats without exponential part (untested):

template<bool fp, long long num, long long denom, char ...> struct literal;

template<bool fp, long long num, long long denom> struct literal<fp, num, denom>
{
   static constexpr double value() { return (1.0*num)/denom; }
};

template<long long num, long long denom, char digit, char... rest>
  struct literal<false, num, denom, digit, rest...>
{
  static constexpr double value()
  {
    return literal<false, 10*num + (digit-'0'), denom, rest...>::value();
  }
};

template<long long num, long long denom, char digit, char... rest>
  struct literal<true, num, denom, digit, rest...>
{
  static constexpr double value()
  {
    return literal<true, 10*num + (digit-'0'), 10*denom, rest...>::value();
  }
};

template<long long num, long long denom, char... rest>
  struct literal<false, num, denom, '.', rest...>
{
  static constexpr double value()
  {
    return literal<true, num, denom, rest...>::value();
  }
};

template<char... c> double operator "" _dbl()
{
  return literal<false, 0, 1, c...>::value();
}

How to extend this to also take an exponential part should be obvious.

Of course one would also want to do some error checking (make sure that the characters are indeed digits).

Pubby
  • 51,882
  • 13
  • 139
  • 180
celtschk
  • 19,311
  • 3
  • 39
  • 64
  • You can get rid of those function calls and make static member variables instead. As long as they're `constexpr`, they can be of non-integral type. – Kerrek SB Nov 13 '11 at 02:18
  • @KerrekSB: Thanks, I didn't know that you could have non-integral local constants via `constexpr`. Makes sense, though. – celtschk Nov 13 '11 at 10:25