Стандарт C ++ 14.8.2 $ 7 гласит:
Подстановка происходит во всех типах и выражениях, которые используются в типе функции и в объявлениях параметров шаблона. Выражения включают в себя не только константные выражения, такие как те, которые появляются в границах массива или в качестве нетиповых аргументов шаблона, но также и общие выражения (то есть неконстантные выражения) внутри
sizeof
,decltype
и другие контексты, которые допускают непостоянные выражения. Замена происходит в лексическом порядке и останавливается, когда возникает условие, которое приводит к сбою дедукции. [Примечание: Эквивалентная замена в спецификациях исключений выполняется только тогда, когда создается спецификация исключений, и в этот момент программа плохо сформирована, если в результате замены получен недопустимый тип или выражение. — конец примечания]
Стандарт предоставляет пример здесь:
template <class T> struct A { using X = typename T::X; };
template <class T> typename T::X f(typename A<T>::X);
template <class T> void f(...) { }
template <class T> auto g(typename A<T>::X) -> typename T::X;
template <class T> void g(...) { }
void h() {
f<int>(0); // OK, substituting return type causes deduction to fail
g<int>(0); // error, substituting parameter type instantiates A<int>
}
Зачем звонить g<int>(0)
здесь ошибка? Не тянется ли тип возврата T::X
причина отказа замены? В чем разница между шаблонами функций f
а также g
?
Ключевые моменты, во-первых,
Замена происходит в лексическом порядке и останавливается, когда условие
что приводит к отказу дедукции встречается
И во-вторых, реализация A<int>
определение вызывает серьезную ошибку, а не ошибку замещения, потому что это приводит к созданию плохо сформированной конструкции typename T::X
(с T == int
) вне непосредственного контекста. [Temp.deduct] / 8:
Только недопустимые типы и выражения в непосредственном контексте
Тип функции и типы параметров шаблона могут привести к
сбой удержания. [ Заметка: Оценка замещенных типов
и выражения могут привести к побочным эффектам, таким как создание экземпляров
специализации шаблона класса и / или шаблона функции
специализации, генерация неявно определенных функций и т. д.
Такие побочные эффекты не находятся в «непосредственном контексте» и могут привести к
программа плохо сформирована. — конечная нота ]
С шаблонами в вопросе, подставляя в typename T::X
в типе функции приводит к ошибке вычета (т. е. SFINAE); подставляя в typename A<T>::X
приводит к серьезной ошибке. Поскольку замена происходит в лексическом порядке, для template <class T> typename T::X f(typename A<T>::X);
это заменяет в typename T::X
во-первых, что приводит к ошибке вычета, и дальнейшая замена не предпринимается. За template <class T> auto g(typename A<T>::X) -> typename T::X;
с другой стороны, он заменяет typename A<T>::X
во-первых, что приводит к серьезной ошибке.
Других решений пока нет …