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?
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.