C++ convert integer to string at compile time
boost, boost-mpl, c++, string, templates
Solution
This can be done using C++14 without any external dependencies. The key addition to the standard is the ability to have non-trivial `constexpr` constructors, allowing the functionality to be contained within a simple class.
Given an integer template parameter, the constructor can carry out the integer-to-string conversion. This is stored in a member character buffer whose size is determined by an additional `constexpr` function. Then, a user-defined conversion provides access to the buffer:
#include <cstdint>
template<std::intmax_t N>
class to_string_t {
constexpr static auto buflen() noexcept {
unsigned int len = N > 0 ? 1 : 2;
for (auto n = N; n; len++, n /= 10);
return len;
}
char buf[buflen()] = {};
public:
constexpr to_string_t() noexcept {
auto ptr = buf + buflen();
*--ptr = '\0';
if (N != 0) {
for (auto n = N; n; n /= 10)
*--ptr = "0123456789"[(N < 0 ? -1 : 1) * (n % 10)];
if (N < 0)
*--ptr = '-';
} else {
buf[0] = '0';
}
}
constexpr operator const char *() const { return buf; }
};
Finally, a variable template (another C++14 addition) simplifies the syntax:
template<std::intmax_t N>
constexpr to_string_t<N> to_string;
puts(to_string<62017>); // prints "62017"
The functionality can be extended to support other bases (e.g. hexadecimal), wide character types, and the common container interface; I've packed this all into a single header and put it on GitHub at tcsullivan/constexpr-to-string.
With C++20, this can also be extended to support floating-point numbers. A container type is needed for the floating-point literal, which previously could not be a template parameter. See the `f_to_string.hpp` header in the GitHub repo for the implementation.
Problem
I want to do something like this: ``` template<int N> char* foo() { // return a compile-time string containing N, equivalent to doing // ostringstream ostr; // ostr << N; // return ostr.str().c_str(); } ``` It seems like the boost MPL library might allow this but I couldn't really figure out how to use it to accomplish this. Is this possible?