How to implement string conversion functions at compile time?

Sentence n4121 looks like it will add the type std::string_literal . It contains a code like:

 template<size_t n> struct string_literal { char data [n]; } 

and

 template <size_t N> constexpr int stoi( const string_literal<N>& str, size_t* idx = 0, int base = 10); 

And here is my Number class:

 template <typename T> struct Number { private: T t; public: constexpr Number(const T& t) : t(t) { } constexpr Number(const std::string& s); constexpr operator T() const { return t; } }; template <> constexpr Number<int>::Number(const std::string& s) : t(std::stoi(s)) { } 

I looked. How to convert a string C to int at compile time? but it only works for strings C. and c_str() not constexpr. Also, this does not cover stol , stoul , stoll , stof , stod ... and so on. Who knows if this offer will turn into a standard. Also, I do not want to wait 3 years for this change of the library to happen. How do I implement it now?


Here is my attempt:

 namespace lib { constexpr bool is_digit(char c) { return c <= '9' && c >= '0'; } constexpr int stoi_impl(const char* str, int value = 0) { return *str ? is_digit(*str) ? stoi_impl(str + 1, (*str - '0') + value * 10) : throw "compile-time-error: not a digit" : value; } constexpr int stoi(const char* str) { return stoi_impl(str); } template<size_t n> struct string_literal { char data [n]; }; template < class charT, size_t N> constexpr string_literal<N> make_string_literal( const charT(&arr)[N]) { string_literal<N> sl; for (std::size_t i = 0; i < N; ++i) sl.data[i] = arr[i]; return sl; } } template <typename T> struct Number { private: T t; public: constexpr Number(const T& t) : t(t) { } constexpr Number(const std::size_t N, const lib::string_literal<N>& s); constexpr operator T() const { return t; } }; template <> constexpr Number<int>::Number(const std::size_t N, const lib::string_literal<N>& s) : t(lib::stoi(s.data)) { } int main() { constexpr auto s = lib::make_string_literal("123456789"); constexpr Number<int> n { sizeof(s.data), s }; return 0; } main.cpp:44:69: error: non-type template argument is not a constant expression constexpr Number(const std::size_t N, const lib::string_literal<N>& s); ^ main.cpp:53:78: error: non-type template argument is not a constant expression constexpr Number<int>::Number(const std::size_t N, const lib::string_literal<N>& s) ^ main.cpp:29:38: error: cannot initialize an array element of type 'char' with an lvalue of type 'const char [10]' return string_literal<N>{arr}; ^~~ main.cpp:60:19: note: in instantiation of function template specialization 'lib::make_string_literal<char, 10>' requested here auto s = lib::make_string_literal("123456789"); 
+5
source share
1 answer

I have implemented a complex compile-time string for scalar converters. Take a look at Constainer::strToFloat and Constainer::strToInt .

Examples from the test pattern file:

 static_assert( strToInt<int>(" 6849.") == 6849 ); static_assert( strToInt<signed char>(" -128aefws") == -128 ); static_assert( strToInt<unsigned>(" \t-0") == 0 ); static_assert( strToInt<unsigned>(" -0x0Xx", 0, 0) == 0 ); static_assert( strToInt<unsigned>(" +0xFF", 0, 0) == 0xFF ); static_assert( strToInt<unsigned>(" +077", 0, 0) == 7+8*7 ); static_assert( strToInt<unsigned>("11000", 0, 2) == 24 ); /**< These should go well on most implementations. */ static_assert( strToFloat<double>("+123.456789e0") == 123.456789 ); static_assert( strToFloat<double>("-0x1.Bc70a3D70A3d7p+6") == -111.11 ); static_assert( strToFloat<double >("-1.18973e+4932") == -std::numeric_limits<double>::infinity() ); static_assert( strToFloat<long double>("-1.18973e+4932") != -std::numeric_limits<long double>::infinity() ); static_assert( strToFloat<double>("-0x.8p-1") == -0.25 ); 
+1
source

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


All Articles