Здравствуйте, zaufi, Вы писали:
Z>собственно вопросы к просвещенной общественности:
Z>0) кто видит разницу в получаемом типе параметра функции `yes_type test(...)`?
Долго шло, но дошло все-таки, и это радует
Начнем по порядку. Для начала разберемся, почему не компилируется пример, приведенный
здесьАвтор: rg45
Дата: 04.03.13
. Еще раз приведу его:
template<typename...>
struct Foo { };
template<typename... Args>
void foo(Foo<Args...>*) { }
int main()
{
foo<int>(nullptr); //error: no matching function for call to 'foo'
}
В данном случае, несущественно, что вместо decltype используется просто шаблон класса с переменный числом параметров. Также понятно, что в оригинальном примере zaufi ошибка компиляции не возникает в силу принципа SFINAE — Substitution Failure Is Not An Error.
Причина такого поведения кроется в том, что для шаблонных функций работает (должно работать по стандарту) частичное выведение шаблонных параметров — при вызове не обязательно указывать полный список шаблонных параметров, достаточно указать только несколько первых параметров, оставшиеся будут выведены из фактических параметров функции:
template<typename...>
struct Foo { };
template<typename... Args>
void foo(Foo<Args...>*) { }
int main()
{
Foo<int, char, double> t;
foo<int>(&t);
}
Обратите внимание, что список шаблонных параметров, указанных при вызове функции лишь частично совпадает со списком фактических параметров типа аргумента. Этот пример успешно компилируют и clang и gcc. Т.о. в случае, когда шаблон функции имеет переменное число параметров, причем эти параметры могут выводиться из фактических параметров функции, возникает конфликт — число параметров, определенных одним и другим способом может оказаться разным. Не удивительно, что компилятор при разрешении этого конфликта отдает предпочтение выведению шаблонных параметров функции по ее фактическим параметрам, потому что этот способ позволяет вывести полный список шаблонных параметров.
Идем дальше. Как только мы используем add_pointer для объявления формального параметра функции:
template<typename... Args>
void foo(typename std::add_pointer<Foo<Args...>>::type) { }
мы тем самым вводим невозможность выведения типа шаблонных параметров из фактических, поскольку определение типа, используемого для формального параметра, оказывается вложенным в класс, и компилятор не может "решить уравнение типов" и вывести внешний тип из внутреннего. Этот вопрос не один раз уже обсуждался на этом форуме, например,
здесьАвтор: rg45
Дата: 24.03.06
и выше по ветке обсуждения. Ну и как только выведение шаблонных параметров перестает работать, компилятор, естественно, начинает использовать параметры, указанные явно, что и является желательным для нашего случая.
Т.о. можно сказать, что gcc себя проявил более строго и последовательно в этом случае по сравнению с clang.