1
votes

Well I am trying to abstract away the std::string/std::wstring annoyances when handling unicode in cross platform applications. As one of the basic things I created a conversion "template":

#ifdef _WIN32
    typedef std::wstring os_string_type;
#else
    typedef std::string os_string_type;
#endif

template <typename OSS_Ty, typename IN_Ty>
OSS_Ty string_convert(const IN_Ty& input);
template <> 
std::wstring string_convert<std::wstring, std::string>(const std::string& input);
template <> 
std::string string_convert<std::string, std::wstring>(const std::wstring& input);

I would use os_string_type as main "string type". However the input is a specific type (either const char* or const wchar_t* - and several "os-specific" function require either a wide string or a normal string.

So for those "interfaces" I created above templates. - The default template if os_string_type is the same as the input/output requirements. And the specific templates to do the conversion.

This seemed to work. However there is a "minor" drawback: as said the input is a character array. Calling: string_conver<std::wstring>(const char*) does invoke however not the specialization. C++ seems to first choose the function type before handling automatic type conversion. (Which I guess is unsurmountable.


So then I wrote another specialization:

template <> 
std::wstring string_convert<std::wstring, char*>(const char* input); 

However now visual studio (2010) gave the following error on compiling:

error C2912: explicit specialization; 'std::wstring string_convert(const char *)' is not a specialization of a function template

How to solve this?

EDIT: the char * const is obviously wrong - it came from const char* (and only changed through reading an "answer" here). I wish to be able to allow constant character arrays where I can't edit the data in the array.

UPDATING code


Actual solution

(which follows quite directly from songyuanyao's post), but I'm posting this here for future references:

#ifdef _WIN32
    typedef std::wstring os_string_type;
#else
    typedef std::string os_string_type;
#endif
typedef char* char_array;
typedef const char* const_char_array;
typedef wchar_t* wchar_array;
typedef const wchar_t* const_wchar_array;

template <typename OSS_Ty, typename IN_Ty>
OSS_Ty string_convert(const IN_Ty& input);
template <> 
std::wstring string_convert<std::wstring, std::string>(const std::string& input);
template <> 
std::string string_convert<std::string, std::wstring>(const std::wstring& input);
template <> 
std::wstring string_convert<std::wstring, const_char_array>(const const_char_array& input);
3
I don't see the point of template functions here. Overload functions seems sufficient.Jarod42
@jarod42: Return type (overloading would mean std::string -> std::wstring as well as std::string -> std::string overload, if I were to "ignore" the type at other places. If the function would only be "conversion" in the true sense it would mean I have to add platform specific (convert vs non convert) at other places in the code - which I'm trying to prevent.paul23

3 Answers

2
votes

The declaration of parameter input mismatched.

change

template <> 
std::wstring string_convert<std::wstring, char*>(char* const input);

to

template <> 
std::wstring string_convert<std::wstring, char*>(char* const & input);

BTW: If you tried with clang, the error message is explicit:

note: candidate template ignored: could not match 'std::basic_string
(char *const &)' against 'std::wstring (char *const)'

1
votes

I would suggest using an overload instead of adding another specialization:

inline std::wstring string_convert(char const *s)
{
    return string_convert<std::wstring, std::string>(s);
}

If your string_convert function internally works on char buffers then you might gain efficiency to have both the template version and this version call the same internal function.

NB. I don't quite see how you plan to use this function -- normally you would have a function that converts to a particular type, as opposed to "toggling" the type of the string.

0
votes

I would do this way:

template <typename OSS_Ty>
OSS_Ty string_convert(const std::string& input);
template <typename OSS_Ty>
OSS_Ty string_convert(const std::wstring& input);

template <>
std::wstring string_convert(const std::string& input) { /* Do the conversion */ }
template <>
std::string string_convert(const std::wstring& input) { /* Do the conversion */ }

template <>
std::string string_convert(const std::string& input) { return input; }
template <>
std::wstring string_convert(const std::wstring& input) { return input; }

and let the conversion from const char* to std::string do the job (as const char* is not a template parameter).