Правильное объявление функции для преобразования из строки ANSI в std :: basic_string <TCHAR> - PullRequest
0 голосов
/ 27 августа 2018

Я попытался объявить функцию, которая преобразует const char * в std :: basic_string следующим образом:

#include <string>
#include <cstring>

#ifdef _MSC_VER
#include <tchar.h>
#else
#define TCHAR char
#endif

typedef TCHAR Char;

typedef std::basic_string<Char> String;

template <typename = typename std::enable_if< !std::is_same<Char, char>::value >::type >
inline String FromACString(const char * p_src)
{
    String dest(std::strlen(p_src), ' ');

    auto p_cur = p_src;

    for (auto & ch : dest)
    {
        ch = *p_cur++;
    }

    return dest;
}

template <typename = typename std::enable_if< std::is_same<Char, char>::value >::type >
inline String FromACString(const char * p_src)
{
    return p_src;
}

но получил ошибки компилятора. Моя идея состояла в том, чтобы иметь две перегрузки и включить одну из них в зависимости от типа TCHAR. Как правильно это сделать?

Ошибка с VC2017:

error C2995: 'String FromACString(const char *)': function template has already been defined

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Майлз ответил, что не так с вашим enable_if. Однако вы можете избежать нюансов enable_if, используя if constexpr:

inline std::basic_string<TCHAR>
FromACString(const char * p_src)
{
    if constexpr (std::is_same_v<TCHAR, char>) {
        // logic for case where TCHAR is char
    } else {
        // logic for case where TCHAR isn't char
    }
}

PS. Ваше преобразование TCHAR в wchar_t (которое, я полагаю, является единственным другим возможным типом, кроме char), вероятно, должно учитывать кодировку символов. Вы можете использовать mbsrtowcs .

0 голосов
/ 27 августа 2018

Ваш код имеет две проблемы:

  1. SFINAE работает только в зависимых контекстах. Поскольку ничего в typename std::enable_if<!std::is_same<Char, char>::value>::type не зависит от каких-либо параметров шаблона, SFINAE не применяется, и вы получаете серьезную ошибку, поскольку std::enable_if<false>::type недопустимо.
  2. При определении «уникальности» шаблонов учитываются только сами типы параметров, а не их значения по умолчанию. У вас есть два определения шаблона функции template <typename> String FromACString(const char*), и это ошибка.

Чтобы исправить первую проблему, вы можете ввести другой параметр шаблона со значением по умолчанию Char. Обычное решение второй проблемы - использование самого выражения enable_if в качестве типа параметра шаблона вместо значения по умолчанию. Это оставляет вас с чем-то вроде этого:

template <typename C = Char,
          std::enable_if_t<!std::is_same<C, char>::value>* = nullptr>
String FromACString(const char* p_src) {
    //...
}

template <typename C = Char,
          std::enable_if_t<std::is_same<C, char>::value>* = nullptr>
String FromACString(const char* p_src) {
    //...
}

Демо-версия

Теперь, в зависимости от того, как определено Char, вы получите один шаблон с подписью

template <typename, void*>
String FromACString(const char*);

и другой, который плохо сформирован и, следовательно, отключен SFINAE.

...