SFINAE с enable_if и перегрузкой - PullRequest
9 голосов
/ 03 июня 2019

Я немного осмотрелся, но не смог найти решение моей конкретной проблемы.

У меня есть код:

template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value || std::is_enum<T>::value, std::string>::type
    convertToString(const T argument) { return std::to_string(argument); }

std::string convertToString(std::string string);

Что должен делать код: используйте версию шаблона для любого числового типа (int, float, double и также ENum) и используйте версию std :: string для всего остального.

Сам код прекрасно компилируется, однако когда я передаю функции класс, который имеет перегрузку operator const char * (которая является жизнеспособным конструктором для std::string), он выдает мне следующую массу сообщений:

no matching function for call to 'SQL_Connection::convertToString(ClassName &)’

candidate: template<class T> typename std::enable_if<(std::is_arithmetic<_Tp>::value || std::is_enum<_Tp>::value), std::__cxx11::basic_string<char> >::type convertToString(T)
 convertToString(const T argument) { return std::to_string(argument); }
 ^~~~~~~~~~~~~~~

template argument deduction/substitution failed:
In substitution of ‘template<class T> typename std::enable_if<(std::is_arithmetic<_Tp>::value || std::is_enum<_Tp>::value), std::__cxx11::basic_string<char> >::type convertToString(T) [with T = ClassName]’:

Я пытался обернуть голову вокруг enable_if и что это делает, но в этот момент я нахожусь в тупике.

Почему он не возвращается к перегрузке std::string, когда он явно не является ни арифметическим, ни ENum?

Если я явно преобразую объект в строковый или константный символ *, он будет работать как положено.

Большое спасибо за помощь.

Дополнительная информация: Я использую C ++ 11 и g ++ 7.3.0 в системе Ubuntu.

1 Ответ

8 голосов
/ 03 июня 2019

Вы используете enable_if правильно, и проблема не в шаблоне функции вообще. Дело в том, что следующее тоже не скомпилируется:

std::string convertToString(std::string string);
struct Foo{
    operator const char*(){...}
};
Foo foo; 
converToString(foo);

Причина в том, что компилятору разрешено выполнять только 1 пользовательское преобразование для каждого переданного параметра, чтобы соответствовать аргументам функции. В этом случае это должно было бы сделать 2 - Foo->const char* и const char*->std::string.

...