Подтвердить что ты не робот

Вывод аргументов шаблона для типа параметра указателя функции с использованием пакета невыделенных параметров

Это похоже на вопрос , но более конкретный случай. На этот раз никакой компилятор не работает.

template<class T>
struct nondeduced
{
    using type = T;
};

template<class T>
using nondeduced_t = typename nondeduced<T>::type;

template<class... T, class U>
void f(void(*)(nondeduced_t<T>..., U)) {}

void g(int, char) { }

int main()
{
    f<int>(g); // error?
}

В приведенном выше примере пакет параметров T не может быть выведен, но компилятор должен иметь возможность выводить U после явной замены аргументов для пакета T (т.е. один int в этом случае).

Ожидается, что вышеизложенное будет работать без трюка nondeduced_t:

template<class... T, class U>
void f(void(*)(T..., U)) {}

Поскольку пакет параметров T уже находится в невыводимом контексте в соответствии с [temp.deduct.type] p5

Невыводимые контексты:

  • Пакет параметров функции, который не встречается в конце списка объявлений-параметров.

К сожалению, ни один компилятор, который я тестировал (g++/clang), не принимал код. В частности, что-то вроде ниже работает как на g++, так и на clang.

template<class... T>
void f(void(*)(nondeduced_t<T>..., char)) {}

И снова это не работает на обоих:

template<class... T>
void f(void(*)(T..., char)) {}

Является ли мое ожидание неправильным?

4b9b3361

Ответ 1

В [temp.deduct.type] p5 один из не-выводимых контекстов -

Пакет параметров функции, который не встречается в конце списка объявлений-параметров.

Пакеты параметров, которые не отображаются в качестве последнего аргумента функций шаблона, никогда не выводятся, но совершенно прав, чтобы указать типы параметров, отключающие вычет. например

template<class T1, class ... Types> void g1(Types ..., T1);

g1<int, int, int>(1,2,3);  // works by non-deduction
g1(1,2,3)                  // violate the rule above by non-deduced context

Но изменяя порядок аргумента функции, даже оставляя параметры шаблона такими, какие они есть, удалите неопределенное условие контекста и сломайте бесконечное расширение пакета параметров. например

template<class T1, class ... Types> void g1(T1, Types ...);
g1(1,2,3)                 // works because its a deduced context.

Есть две причины, по которым ваш код не компилируется:

  • Порядок аргументов функции создает не-выводимый-контекст, который вызывает тип пакета параметров T в шаблоне, указанном в функции f, никогда не будет быть выведено.

  • Параметр шаблона T отображается только как определители в аргументах функции (например, nondeduced_t), а не непосредственно указан как аргумент функции (который позволяет вычесть аргумент).

Чтобы сделать компиляцию кода, вы либо разместите расширение пакета параметров, либо запустив nondeduced_t косвенным, как

template<class... T,class U>
void f( void(*)(U,T...) ) { }

f(g);

или изменить порядок параметров шаблона и указать аргумент шаблона при вызове функции, как

template<class U,class... T>
void f( void(*)(U,typename nondeduced<T>::type...) ) {}

f<int,char>(g);