Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using template to handle string and wstring

I have following two functions:

void bar(const std::string &s)
{
    someCFunctionU(s.c_str());
}

void bar(const std::wstring &s)
{
    someCFunctionW(s.c_str());
}

Both of these call some C function which accepts const char * or const wchar_t * and have U or W suffixes respectively. I would like to create a template function to handle both of these cases. I tried following attempt:

template <typename T>
void foo(const std::basic_string<T> &s)
{
    if constexpr (std::is_same_v<T, char>)
        someCFunctionU(s.c_str());
    else
        someCFunctionW(s.c_str());
}

But this does not seem to work correctly. If I call:

foo("abc");

this will not compile. Why is that? why a compiler is not able to deduce the proper type T to char? Is it possible to create one function which would handle both std::string and std::wstring?

like image 882
Igor Avatar asked Nov 20 '18 18:11

Igor


People also ask

Should I use string or Wstring?

These are the two classes that you will actually use. std::string is used for standard ascii and utf-8 strings. std::wstring is used for wide-character/unicode (utf-16) strings. There is no built-in class for utf-32 strings (though you should be able to extend your own from basic_string if you need one).

What is the purpose of template parameter?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

How do you get a substring of Wstring?

std::wstring wstr = L"This is a Wide String"; wstring has methods to assign, copy, align, replace or to operate with other wide strings. These methods can be used in all string methods with their appropriate syntax. We can retrieve a substring of a wide string by using substr() method.

How do you append in Wstring?

BTW: Instead of using append(), you can use += to append to a string: wstring s; s += L"foo"; s += "bar"; .


1 Answers

this will not compile. Why is that? why a compiler is not able to deduce the proper type T to char?

As better explained by others, "abc" is a char[4], so is convertible to a std::basic_string<char> but isn't a std::basic_string<char>, so can't be deduced the T type as char for a template function that accept a std::basic_string<T>.

Is it possible to create one function which would handle both std::string and std::wstring?

Yes, it's possible; but what's wrong with your two-function-in-overloading solution?

Anyway, if you really want a single function and if you accept to write a lot of casuistry, I suppose you can write something as follows

template <typename T>
void foo (T const & s)
{
    if constexpr ( std::is_same_v<T, std::string> )
        someCFunctionU(s.c_str());                       
    else if constexpr ( std::is_convertible_v<T, char const *>)
        someCFunctionU(s);
    else if constexpr ( std::is_same_v<T, std::wstring> )
        someCFunctionW(s.c_str());
    else if constexpr ( std::is_convertible_v<T, wchar_t const *> )
        someCFunctionW(s);
    // else exception ?
}

or, a little more synthetic but less efficient

template <typename T>
void foo (T const & s)
{
    if constexpr ( std::is_convertible_v<T, std::string> )
        someCFunctionU(std::string{s}.c_str());
    else if constexpr (std::is_convertible_v<T, std::wstring> )
        someCFunctionW(std::wstring{s}.c_str());
    // else exception ?
}

So you should be able to call foo() with std::string, std::wstring, char *, wchar_t *, char[] or wchar_t[].

like image 151
max66 Avatar answered Oct 02 '22 10:10

max66