Now I have written it so that it can convert int
to std::string
, std::wstring
(and to std::u16string
, std::u32string
when >=C++11
is being used):
#include <string> // std::string, std::wstring
#include <cstdio> // std::sprintf
#include <cwchar> // std::mbstate_t, std::swprintf
#include <climits> // CHAR_BIT
#include <cassert> // assert()
#if __cplusplus >= 201103L
//These will be included if >=C++11 is used
#include <codecvt>
#include <locale> // std::wstring_convert
#endif
template<bool B, typename T = void>
struct EnableIf{};
template<typename T>
struct EnableIf<true, T>{typedef T Type;};
template<typename T1, typename T2>
struct IsSame{ static const bool value = false; };
template<typename T>
struct IsSame<T,T>{ static const bool value = true; };
#if __cplusplus >= 201103L
///Convenience wrapper of std::codecvt (`>=C++11`)
template <class internT, class externT, class stateT>
struct Codecvt : std::codecvt<internT,externT,stateT>
{ ~Codecvt(){} };
///@struct ConvUTF
///`UTF-8 <> UTF-16` and `UTF-8 <> UTF32` converter (`>=C++11`).
template<typename Char_T>
struct ConvUTF { typedef std::wstring_convert<Codecvt<Char_T, char, std::mbstate_t>, Char_T> Converter; };
#endif
///@struct ConvInt
///Contains a function to convert integer to string (either `std::string`
///or `std::wstring` ( or `std::u16string` or `std::u32string` for >=C++11)
///@tparam Char_T Basic character type (`char`, `wchar`, `char16_t`, `char32_t`).
template<typename Char_T, typename T = Char_T> struct ConvInt{};
template<typename Char_T> struct ConvInt<Char_T, typename EnableIf<
IsSame<Char_T, char>::value|IsSame<Char_T, wchar_t>::value, Char_T>::Type>{
//wrapper of sprintf or swprintf
static int mysprint(Char_T*, size_t size, int x);
///Converts an integer to std::string/std::wstring
///@param x the integer to convert
///@return std::string/std::wstring from the integer
static std::basic_string<Char_T> toString(int x){
Char_T buf[sizeof(int)*CHAR_BIT]; //sizeof(int)*CHAR_BIT should always be sufficient
int written = mysprint(buf, sizeof(buf), x);
assert(written > 0);
return std::basic_string<Char_T>(buf);
}
};
template<> inline int ConvInt<char>::mysprint(char* buf, size_t size, int x){
return sprintf(buf, "%d", x);
}
template<> inline int ConvInt<wchar_t>::mysprint(wchar_t* buf, size_t size, int x){
return swprintf(buf, size, L"%d", x);
}
#if __cplusplus >= 201103L
template<typename Char_T> struct ConvInt<Char_T, typename EnableIf<
IsSame<Char_T, char16_t>::value|IsSame<Char_T, char32_t>::value, Char_T>::Type>{
///Converts integer to std::u16string/std::u32string.
///Uses codecvt for conversion.
///@param x int to convert
///@return std::u16string/std::u32string from the integer
static std::basic_string<Char_T> toString(int x){
std::string s = std::to_string(x);
typename ConvUTF<Char_T>::Converter conv;
return conv.from_bytes(s);
}
};
#endif
Usage example:
int main(){
std::cout<<"\nstring: "<<ConvInt<char>::toString(-48);
std::wcout<<"\nwstring: "<<ConvInt<wchar_t>::toString(-2147483647);
#if __cplusplus >= 201103L
ConvUTF<char16_t>::Converter conv;
ConvUTF<char32_t>::Converter conv2;
std::cout<<"\nu16string: "<<conv.to_bytes(ConvInt<char16_t>::toString(-48));
std::cout<<"\nu32string: "<<conv2.to_bytes(ConvInt<char32_t>::toString(-48));
#endif
return 0;
}
sizeof(int) * CHAR_BIT
(which is incorrect, as it doesn't correlate like this, to the max number of digits in an integer. Still, the solution will work. also, be careful about swallowing errors on failure: This version will keep working and simply provide invalid results to client code (I don't know your use case - maybe this is what you need, but it makes me wary :) ). \$\endgroup\$