У меня есть следующий пример кода:
class Serializable {};
class MyData : public Serializable {};
void GetData( Serializable& ) {}
template<typename T>
void GetData( T& data )
{
std::istringstream s{"test"};
s >> data;
}
int main()
{
MyData d;
GetData(d);
}
Основываясь на правилах разрешения перегрузки, предпочтительна не шаблонная версия, потому что базовый класс имеет тип Serializable
, Тем не менее, я ожидаю, что SFINAE сработает, когда в версии шаблона возникнут ошибки, когда он создается для разрешения перегрузки (потому что, если для типа не определен оператор >>, это не должно учитываться).
Почему по-прежнему происходит сбой, даже если шаблон не будет использоваться?
Исходя из правил разрешения перегрузки, не шаблонная версия должна быть
предпочтительнее, потому что базовый класс имеет типSerializable
,
Не совсем. [Over.match.best]:
Учитывая эти определения, жизнеспособная функция
F1
определяется как
лучшая функция, чем другая жизнеспособная функцияF2
если для всех аргументов
i, ICSi (F1) не хуже последовательности преобразования, чем ICSi (F2), а затем
- для некоторого аргумента j ICSj (F1) является лучшей последовательностью преобразования, чем ICSj (F2), или, если не это,
- […]
F1
не специализация шаблона функции иF2
это специализация шаблона функции […]
Это означает, что только если выводимая специализация шаблона функции требует преобразования, которое не лучше, чем преобразование, которое требует нормальная функция, применяется ваше правило.
И привязка d
в Serializable&
является худшим преобразованием, чем привязка d к MyData&
(это тип параметра специализации), [over.ics.ref]:
Когда параметр ссылочного типа привязывается напрямую (8.5.3) к
выражение аргумента, неявная последовательность преобразования является тождеством
преобразование, если выражение аргумента не имеет тип, который является
производный класс типа параметра, в этом случае неявный
последовательность преобразования представляет собой преобразование из базы в производную (13.3.3.1).
Тем не менее, я ожидаю, что SFINAE начнет действовать, когда в
версия шаблона, когда он создается для разрешения перегрузки
(потому что если оператор >> не определен для типа, он не должен
быть принятым во внимание).
SFINAE не распространяется на содержание шаблона функции. [Temp.deduct] / 8:
Только недопустимые типы и выражения в непосредственном контексте
тип функции и типы параметров шаблона может привести к
сбой удержания.
Следовательно, выведенная специализация шаблона функции действительно выбрана и вызывает ошибку компилятора при создании его определения.