I have a template class in C++ which takes as a char_type
template parameter the character type, such as char
, wchar_t
, char32_t
, etc... The class then use std::basic_string<char_type>
in the code.
Then somewhere in the class I fill a table of escaping sequences such as "&"
. This does not work as depending on the template character type, we would need to use "&"
, L"&"
, U"&"
...
Is there a way to avoid specializing the template functions for initializing the table, for instance with some standard function for converting string litterals?
As these are escaping sequences, they do not contain anything else than ASCII characters.
I would do the following:
template <typename char_type, size_t LENGTH>
constexpr std::basic_string<char_type> literal(const char (&value)[LENGTH])
{
using string = std::basic_string<char_type>;
string result{};
result.reserve(LENGTH);
std::copy(std::begin(value), std::end(value), std::back_inserter(result));
return result; // rvo
}
You can use it this way:
// Table of escaping sequences
std::basic_string<char_type> escaping_sequences[] =
{
literal<char_type>("&"),
literal<char_type>("&foo"),
literal<char_type>("&bar"),
...
}
I've tested it in Ideone:
literal< char >("test") // result: std::string
literal<char32_t>("test") // result: std::basic_string<char32_t, std::char_traits<char32_t>, std::allocator<char32_t> >
literal<char16_t>("test") // result: std::basic_string<char16_t, std::char_traits<char16_t>, std::allocator<char16_t> >
Is untested for all the char types but hope it helps.
My bad, I just noticed that galinette almost answered the same as me before I did. The only difference between my code and the one from galinette is that I'm allocating the resulting string once with counting the number of characters at compile time, due to the use of reserve
instead of using the automatic allocation of push_back
LENGTH
as a template parameter.
It is possible to avoid the final null character issue by substracting 1 to the end
iterator:
template <typename char_type, size_t LENGTH>
constexpr std::basic_string<char_type> literal(const char (&value)[LENGTH])
{
using string = std::basic_string<char_type>;
string result{};
result.reserve(LENGTH - 1);
std::copy(std::begin(value), std::end(value) - 1, std::back_inserter(result));
return result; // rvo
}
Or, using std::copy_n
instead of std::copy
:
template <typename char_type, size_t LENGTH>
constexpr std::basic_string<char_type> literal(const char (&value)[LENGTH])
{
using string = std::basic_string<char_type>;
string result{};
result.reserve(LENGTH - 1);
std::copy_n(std::begin(value), LENGTH - 1, std::back_inserter(result));
return result; // rvo
}
The best way is maybe to define conversion function ourselves, as converting ASCII to UTF8/16/32 is a straightforward cast on the char types
template<typename char_type>
std::basic_string<char_type> cvtASCIItoUTFX(const char * litteral)
{
//We could define a faster specialization in case char_type is char
size_t s = strlen(litteral);
std::basic_string<char_type> result;
result.reserve(s);
for(size_t i=0;i<s;++i)
{
result.push_back((char_type)litteral[i]);
}
return result;
}
As these are escaping sequences, they do not contain anything else than ASCII characters.
Is there a way to avoid specializing the template functions for initializing the table, for instance with some standard function for converting string litterals?
No, because the standard doesn't have any conversion functions that stick to such specific subsets.
I'd recommend just using an external generator for the table, or if you really want to stay within C++, to use macros.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With