Вы, вероятно, уже пришли к выводу, что компилятор не выведет TBody
, изучив тип sample.member
. Это добавило бы еще один уровень сложности к алгоритму вывода шаблона.
Алгоритм сопоставления шаблонов учитывает только функции подписи , а не их тела. Хотя это и используется не слишком часто, вполне законно просто объявить шаблонную функцию без предоставления тела:
template <typename T> void f(T param);
Это удовлетворяет компилятору. Чтобы удовлетворить компоновщик, вы, конечно, должны также где-то определить тело функции и убедиться, что все необходимые экземпляры были предоставлены. Но тело функции не обязательно должно быть видимым для клиентского кода функции шаблона, если требуемые экземпляры доступны во время ссылки. Тело должно было бы явно создать экземпляр функции, например:
template <> void f(int param);
Но это только частично относится к вашим вопросам, потому что вы можете представить себе сценарий, подобный следующему, где 2-й параметр может быть выведен из предоставленного параметра по умолчанию и который не будет компилироваться:
template<typename TArg, typename TBody>
void g(TArg param, TBody body = param.member); // won't deduce TBody from TArg
Алгоритм сопоставления шаблонов учитывает только фактический тип, а не любые потенциальные вложенные типы элементов в случае классов или структур. Это добавило бы еще один уровень сложности, который, по-видимому, был признан слишком сложным. Где должен остановиться алгоритм? Члены членов и так далее также должны рассматриваться?
Кроме того, это не требуется, поскольку существуют другие способы достижения того же намерения, как показано в примере ниже.
Ничто не мешает вам писать:
struct sample
{
typedef int MemberType;
MemberType member;
};
template<typename TArg>
void g(TArg param)
{
typename TArg::MemberType v = param.member;
}
sample s = { 0 };
g(s);
для получения того же эффекта.
Относительно вашего сэмпла, который вы добавили после редактирования: хотя кажется, что h(p.member)
зависит от члена структуры, и, следовательно, алгоритм сопоставления с шаблоном должен дать сбой, это не так, потому что вы сделали его двухэтапным процессом:
- Увидев
g(s);
, компилятор ищет любую функцию, принимающую аргумент типа sample
(с шаблоном или без!). В вашем случае наилучшее совпадение - void g(T p)
. На данный момент компилятор даже не посмотрел на тело g(T p)
! .
- Теперь компилятор создает экземпляр
g(T p)
, специализированный для T: sample
. Поэтому, когда он видит h(p.member)
, он знает, что p.member
имеет тип int
, и попытается найти функцию h()
, принимающую аргумент типа int
. Ваша функция шаблона h(T p)
оказывается наилучшим соответствием.
Обратите внимание, что если вы написали (обратите внимание на NOT_A_member ):
template<typename T>
void g(T p)
{
h(p.NOT_A_member);
return;
}
тогда компилятор все равно будет считать g()
действительным соответствием на этапе 1. Вы получите ошибку, когда выяснится, что sample
не имеет члена с именем NOT_A_member
.