1

I would like to code a function that would look like:

template <typename CharT>
std::basic_string<CharT> convert(char const *);

and be used as follows:

convert<char>("Hello World!");     //  "Hello World!"
convert<wchar_t>("Hello World!");  // L"Hello World!"
convert<char16_t>("Hello World!"); // u"Hello World!"
convert<char32_t>("Hello World!"); // U"Hello World!"

I could use std::codecvt and co, but I find it almost pointless as it would be so easier to use some macro that adds L, u or U with 0 cost.

Unfortunately templates and macros don't act at the same level... So here comes my question: would there be some way to mix them ? Or is there a better way ?

My main goal is to avoid repetition (specialization) of code: some functions I'm coding are CharT templated and use string literals, and that would be the only difference. As an example:

template <typename CharT>
void foo (std::vector<std::basic_string<CharT>> const & vec, 
          std::basic_string<CharT> str = convert<CharT>("default"));

That would avoid to specialize foo() for each char type.

Many thanks for your help

O'Neil
  • 3,790
  • 4
  • 16
  • 30
  • 1
    I don't see the need for specialization here, just use e.g. `codecvt` with `char` as the "source" type and `CharT` as the "destination" type? – Some programmer dude Jul 18 '15 at 14:50
  • Indeed, I was already thinking about later. Edited, thanks. – O'Neil Jul 18 '15 at 15:08
  • @JoachimPileborg Yeah but that's still runtime computation. The OP wants to avoid that since they're string literals and adding a certain prefix would do the trick. – edmz Jul 18 '15 at 15:09
  • In that case, wouldn't macros be the only way? I'm not certain, but I think the macro concatenation operator `##` can attach a prefix to a string constant. Unless this can be done with `operator""`? I doubt it though. – celticminstrel Jul 18 '15 at 15:21
  • @celticminstrel The problem is that you can't have a macro that does different things depending on type, so you need to use multiple macros with different names, which seems to be what the OP wants to avoid. The only way I can see this being done is with a template function which unfortunately can't be `constexpr` (and therefore possible to evaluate at compile-time). – Some programmer dude Jul 18 '15 at 15:31
  • I already thought about such macros, but the problem is that they would be dependant of a template type, which is unfortunately not possible. – O'Neil Jul 18 '15 at 15:49
  • 1
    Use only one type of string literals (for example u8"default") and only one type of std::basic_string (for example std::string that contains utf8) all over your program logic. Then the problem stops existing itself. – Öö Tiib Jul 18 '15 at 15:59

2 Answers2

0

Edited: This will work from C++11. Since operator cannot be template you can change the operator overload to your convert function.

#include <string>

std::basic_string<char> operator ""_s(const char * str, std::size_t len) {
    return std::basic_string<char> (str, str + len);
}

std::basic_string<char16_t> operator ""_u(const char * str, std::size_t len) {
    return std::basic_string<char16_t> (str, str + len);
}

std::basic_string<char32_t> operator ""_U(const char * str, std::size_t len) {
    return std::basic_string<char32_t> (str, str + len);
}

std::basic_string<wchar_t> operator ""_L(const char * str, std::size_t len) {
    return std::basic_string<wchar_t> (str, str + len);
}


int main() {
    std::string s1    = "Hello World!"_s;
    std::u16string s2 = "Hello World!"_u;
    std::u32string s3 = "Hello World!"_U;
    std::wstring s4   = "Hello World!"_L;
    return 0;
}

See LIVE DEMO working.

Shreevardhan
  • 12,233
  • 3
  • 36
  • 50
  • Thanks for your answer, but I'm afraid that you would need to prefix the literals with `L`, `u` or `U` (exactly what I want to avoid). Here you are only generating std::basic_strings. – O'Neil Jul 18 '15 at 15:42
  • @JemCpp I won't need to prefix anything, only suffix a `s` or `_s`. – Shreevardhan Jul 18 '15 at 15:52
  • Have a look at [this ideone](https://ideone.com/4Q1ptE) and [documentation](http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s) : parameters are `char`, `wchar_t`, `char16_t` and `char32_t`, not only `char`. – O'Neil Jul 18 '15 at 15:58
  • Ok, there is an improvement in your edited code, but still a problem : this doesn't produce the same Xstring. Make a comparison between `std::wstring(L"Jérémy")` and `"Jérémy"_L` (see [demo](https://ideone.com/YhVYg4)) I may though accomodate with it as I have very few chances of using accents or particular characters. – O'Neil Jul 18 '15 at 17:54
0

I finally got the idea of using macros to generate every 4 overloads of the function foo.

template <typename CharT>
void foo (std::vector<std::basic_string<CharT>> const & vec, 
          std::basic_string<CharT> str = convert<CharT>("default"));

becomes

#define FOO(CharT, prefix) \
void foo (std::vector<std::basic_string<CharT>> const & vec, \
          std::basic_string<CharT> str = prefix ## "default");

and I just have to add

FOO(char, )
FOO(wchar_t, L)
FOO(char16_t, u)
FOO(char32_t, U)

four lines that I can also put into another macro GENERATE so I can simply call

GENERATE(FOO)

I know macros... but I've reached my main goal to avoid code repetition. :-)

Thanks everybody for your help!

O'Neil
  • 3,790
  • 4
  • 16
  • 30