How to convert char template arguments from user literals back to numeric types?

This question is being asked because of this .

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

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

This means that 503_suffix will become <'5','0','3'>

This is good, although it is not very useful in the form in which it is found.

How to convert this back to a numeric type? . This would turn <'5','0','3'> into constexpr 503 . In addition, it should also work with floating point literals. <'5','.','3> will turn into int 5 or float 5.3

A partial solution was found in the previous question , but it does not work with non-integer ones:

 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 
+4
source share
2 answers

I think the following should work on floats without the 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 the exponential part should be obvious.

Of course, you also need to do some error checking (make sure that the characters are really numbers).

+3
source

There is an easy way. The non-type parameter package can be expanded into the 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; } 
+4
source

Source: https://habr.com/ru/post/1380962/


All Articles