Предположим, у меня есть шаблон класса / структуры вместе с явным руководством по выводам для его конструктора. Пусть у этого класса есть два параметра шаблона, один из которых может быть выведен с помощью руководства по дедукции, а другой - нет.
template <int Q, typename T>
struct Foo {
template <typename F>
Foo(F&&) { }
};
template <typename T>
using alias = T;
template <typename T>
struct alias2 { using type = T; };
template <int Q, typename F>
Foo(F&& f) -> Foo<Q, alias<F>>; // deduction guide, but cannot deduce Q yet
template <typename T>
using Bar = Foo<1, T>; // create alias that fixes Q
/* This should generate a deduction guide for Bar<T> by first
"copying" Foo's deduction guide, deducing from Foo<Q, alias<F>>
and Foo<1, T> that Q=1 and T=alias<F>=F, thus generating
<template F>
Bar(F&&) -> Bar<1, F>;
if this was correct syntax. */
int main() {
Bar f{ 5 };
}
Если я сейчас создаю псевдоним, который будет явно указывать ранее невыводимый параметр, насколько я понимаю , неявно сгенерированное руководство по выводу этого псевдонима должно иметь возможность полностью вывести оба аргумента шаблона (по правилам стандартного вывода аргументов шаблона), даже если один тип не выводится в шаблоне определяющего класса.
Но что я могу сделать в сценарии, где я использую не alias
, а alias2
, т.е. изменить руководство по выводам на
template <int Q, typename F>
Foo(F&& f) -> Foo<Q, typename alias2<F>::type>;
Согласно документации , теперь это будет вводить невыявленный контекст (поскольку параметр шаблона появляется left для оператора области ::
), поэтому вывод аргумента шаблона для T=F
должен выйти из строя (что очевидно делает ).
Вопрос 1: Если эта теория верна, что я могу с этим поделать? Предположим, я хочу использовать не тривиальный псевдоним идентичности, а более сложное преобразование типа, которое в конечном итоге будет иметь форму typename transformation<Input>::result
в руководстве по выводам.
Вопрос 2: Даже теперь моя теория терпит неудачу, когда я полностью удаляю Q, поскольку следующий код будет принят (G CC -10 / 11):
template <typename T>
struct Foo {
template <typename F>
Foo(F&&) { }
};
template <typename T>
struct alias2 { using type = T; };
template <typename F>
Foo(F&& f) -> Foo<typename alias2<F>::type>;
template <typename T>
using Bar = Foo<T>;
template <typename T>
void some(typename alias2<T>::type) { }
int main() {
Bar f{ 5 };
}
Почему компилятор может вывести T из F даже если это невыведенный контекст?