In C++, is it possible to generate an integer from a string literal using only compile-time facilities ?
For instance, if all we have is the literal "6", is there some way to use it as a template argument, like std::array<GET_INTEGER("6")> a;
?
I know about constexpr
-based techniques, such as :
template <int N> constexpr char get_char(const char s[N], int n) {
return s[n];
}
However constexpr
isn't ready yet on most compilers, so I'm looking for solutions using probably macros and TMP.
It's just for experimentation, so crazy ideas are welcome.
Apparently gcc allows "abcd"[3]
be interpreted as 'd'
, which allows this to work (at least on g++-4.6 and 4.7):
#include <boost/preprocessor/repetition/enum.hpp>
template <const char... characters>
struct GetIntegerTemplate;
template <const char head, const char... rest>
struct GetIntegerTemplate<head, rest...>
{
typedef GetIntegerTemplate<rest...> Prev;
enum
{
power = Prev::power * 10,
value = (head - '0') * Prev::power + Prev::value
};
};
template <>
struct GetIntegerTemplate<>
{
enum
{
power = 1,
value = 0
};
};
#define GET_NTH_CHARACTER(z, n, data) data[n]
#define GET_INTEGER(length, the_string) GetIntegerTemplate<BOOST_PP_ENUM(length, GET_NTH_CHARACTER, the_string)>::value
int main()
{
static_assert(GET_INTEGER(7, "1234567") == 1234567, "oops");
}
But it won't compile on clang, which says "non-type template argument of type 'const char' is not an integral constant expression".
What it really does is to break down the string literal "1234567"
into a list of character literals '1', '2', '3', '4', '5', '6', '7'
. The instantiation
GetIntegerTemplate<'1', '2', '3', '4', '5', '6', '7'>::value
is then invoked to turn the list into an integer 1234567. The string → char literal step may involve non-standard behavior which may not work outside of g++ (i.e. worse than constexpr
☺), but that GetIntegerTemplate<...>::value
is portable.