paul23
paul23

Reputation: 9435

Function template specialization - problems with pointers

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);

Upvotes: 1

Views: 637

Answers (3)

Jarod42
Jarod42

Reputation: 217245

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).

Upvotes: 0

songyuanyao
songyuanyao

Reputation: 172924

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)'

Upvotes: 2

M.M
M.M

Reputation: 141554

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.

Upvotes: 1

Related Questions