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;
You can use it as follows:
// Table of escaping sequences std::basic_string<char_type> escaping_sequences[] = { literal<char_type>("&"), literal<char_type>("&foo"), literal<char_type>("&bar"), ... }
I 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> >
Not tested for all char types, but hope this helps.
Change 1
My bad one, I just noticed that the galinette answered almost the same way as I did. The only difference between my code and one of galinette is that I distribute the received string once using reserve instead of automatically distributing push_back by counting the number of characters at compile time, due to the use of LENGTH as a template parameter.
Edit 2
You can avoid the final null character error by subtracting 1 in the 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;
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;