Ответ 1
template<class T> void f(T,
typename size_map<sizeof(&U::foo)>::type* = 0);
Это не работает, потому что U
не участвует в выводе. В то время как U
является зависимым типом, во время вычитания для f
он обрабатывается как фиксированный тип, записанный с независящим именем. Вам нужно добавить его в список параметров f
/* fortunately, default arguments are allowed for
* function templates by C++0x */
template<class T, class U1 = U> void f(T,
typename size_map<sizeof(&U1::foo)>::type* = 0);
Итак, в вашем случае, потому что U::foo
не зависит от параметров самого f
, вы получаете сообщение об ошибке, неявно создавая экземпляр S<X>
(попробуйте прокомментировать вызов, и он все равно должен потерпеть неудачу). FCD говорит в 14.7.1/1
Неявное инстанцирование специализации шаблона шаблона вызывает неявное создание объявлений, но не определений или аргументов по умолчанию, функций-членов класса, классов-членов, статических элементов данных и шаблонов-членов;
То есть, если вы неявно создаете экземпляр S<X>
, будет объявлено следующее выражение шаблона функции
template<class T> void S<X>::f(T,
typename size_map<sizeof(&X::foo)>::type* = 0);
Анализ этого объявления шаблона затем обнаружит, что он не может разрешить ссылку на X::foo
и ошибку. Если вы добавите U1
, объявление шаблона еще не попытается решить ссылку на U1::foo
(так как U1
является параметром f
) и, таким образом, останется в силе и SFINAE, когда f
будет пытаться называться.