Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use string litterals in a "char type" templated class

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 "&amp;". This does not work as depending on the template character type, we would need to use "&amp;", L"&amp;", U"&amp;"...

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.

like image 250
galinette Avatar asked Sep 29 '15 09:09

galinette


3 Answers

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>("&amp"),
    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.

Edit 1

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 reserve instead of using the automatic allocation of push_back counting the number of characters at compile time, due to the use of LENGTH as a template parameter.

Edit 2

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
}
like image 190
PaperBirdMaster Avatar answered Nov 18 '22 14:11

PaperBirdMaster


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;
}
like image 22
galinette Avatar answered Nov 18 '22 15:11

galinette


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.

like image 1
R. Martinho Fernandes Avatar answered Nov 18 '22 13:11

R. Martinho Fernandes