Недавно я создал этот примерный код, чтобы проиллюстрировать использование функции вариационного шаблона С++ 11.
template <typename Head, typename... Tail> void foo (Head, Tail...);
template <typename... Tail> void foo (int, Tail...);
void foo () {}
template <typename... Tail>
void foo (int x, Tail... tail)
{
std :: cout << "int:" << x;
foo (tail...);
}
template <typename Head, typename... Tail>
void foo (Head x, Tail... tail)
{
std :: cout << " ?:" << x;
foo (tail...);
}
foo (int (123), float (123)); // Prints "int:123 ?:123.0"
Если первые две строки, которые forward-declare foo
опущены, то вместо этого печатается int:123int:123
. Это удивило некоторого опытного и знающего программиста на С++.
Он был убежден, что форвардные декларации не должны быть необходимы, потому что тело не будет создаваться до второй фазы двухфазного поиска. Он считает, что компилятор (gcc 4.6) имеет ошибку.
Я считаю, что компилятор прав, потому что два foo
являются различными базовыми функциями шаблона, и выбор базового шаблона должен быть заблокирован - на первом этапе, иначе вы можете нарушить правило одного определения, создав экземпляр foo
, прежде чем все его версии будут определены, а затем снова (подумайте, как компоновщик предполагает, что избыточные определения функции шаблона идентичны, взаимозаменяемы и отбрасываются).
Итак, кто прав?
Вышеупомянутый GOTW прекрасно объясняет, как и почему шаблоны функций не частично специализируются, но существование вариационных функций шаблонов, похоже, добавляет к путанице - интуиция, что foo<int,Tail...>
должна быть частичной специализацией foo<Head,Tail...>
сильнее, чем эта интуиция для невариантных функций, по крайней мере для меня.