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?
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).
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.
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.
BTW: Instead of using append(), you can use += to append to a string: wstring s; s += L"foo"; s += "bar"; .
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[]
.
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