расширение пакета с несколькими параметрами gcc и clang

63
3

Я пытаюсь использовать variadics для преобразования функции N параметров в функцию параметров 2^N Следующий фрагмент nvcc 8.0 компилируется clang 3.9, в то время как nvcc 8.0 (эффективно gcc 5.4) терпит неудачу с ошибкой:

error: no instance of overloaded function "foo" matches the argument list

код:

template<class... Ts> struct Typelist{};

template <class..., class... Us>
void foo(Typelist<>, Typelist<Us...>, Us... us ){
// do the actual work
}

template <class T, class... Ts, class... Us>
void foo(Typelist<T, Ts...>, Typelist<Us...>, T t, Ts... ts, Us... us){
foo(Typelist<Ts...>{}, Typelist<Us..., Us...>{}
, ts..., us..., (us+t)...);
}

template <class... Ts>
void bar(Ts... ts){
foo(Typelist<Ts...>{}, Typelist<unsigned>{}
, ts..., 0u);
}

называемый

int main(int /*argc*/, char */*argv*/[])
{
bar(2u);
bar(2u, 3u, 4u);

return 0;
}

Я делаю что-то неправильно? Как мне заставить работать с gcc?

спросил(а) 2021-01-19T19:18:21+03:00 6 месяцев, 1 неделя назад
1
Решение
79

Этот код работает от [temp.deduct.type]:

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

как в:

template<class D0, class... Ds, class... Is>
HOST_DEVICE void _apply(Typelist<D0, Ds...> , D0 d0, Ds... ds, Is... is) {
// ~~~~~~~~

и [temp.arg.explicit]:

Исходный шаблон шаблонов шаблонов (14.5.3), не выведенный иначе, будет выведен на пустую последовательность аргументов шаблона.

Эта идея deduce-nededuced-packs-as-empty разбивает ваш код как на gcc, так и на clang по-разному. Рассмотрим apply(1,2) вызова apply(1,2):

    каждая версия gcc, которую я пробовал, рассматривает Ds... ds pack empty и выводит Ds... как <int> и Is... as <int, unsigned int>. Так что перегрузка выбрасывается, так как она принимает 5 аргументов, и мы проезжаем только 4. каждая версия clang, которую я пробовал, выводит второй Ds... как <int> из первого аргумента и <> из пакета и рассматривает вывод как неудачу из-за несогласованности.

В любом случае, здесь нет пути.

Вместо этого вы можете перевернуть заказ и сначала поместить все Is... Поскольку вы знаете все типы, вы можете явно указать их, и пусть Ds... будет выведено. То есть:

template<class... Is>
HOST_DEVICE void _apply(Is..., Typelist<>)
{
// ...
}

template<class... Is, class D0, class... Ds>
HOST_DEVICE void _apply(Is... is, Typelist<D0, Ds...> , D0 d0, Ds... ds) {
_apply<Is..., decltype(std::declval<Is>()+std::declval<D0>())...>(
is...,
(is+d0)...,
Typelist<Ds...>{},
ds...);
}

template<class... Ds>
HOST_DEVICE void apply(Ds... ds) {
_apply<unsigned int>(0u, Typelist<Ds...>{}, ds...);
}

Это работает на каждом компиляторе.

ответил(а) 2021-01-19T19:18:21+03:00 6 месяцев, 1 неделя назад
46

Поэтому я немного сыграл с кодом и придумал 3 версии:

Компиляция в clang, не выполняется с помощью gcc:

template <class..., class... Us>
void foo(Typelist<>, Typelist<Us...>, Us... us ){ /*do the stuff*/ }

template <class T, class... Ts, class... Us>
void foo(Typelist<T, Ts...>, Typelist<Us...>, T t, Ts... ts, Us... us){
foo(Typelist<Ts...>{}, Typelist<Us..., Us...>{}, ts..., us..., (us+t)...);
}

template <class... Ts>
void bar(Ts... ts){
foo(Typelist<Ts...>{}, Typelist<unsigned>{}, ts..., 0u);
}

Интересно, что для этого требуются оба списка типов, хотя кажется, что одного достаточно, чтобы устранить двусмысленность.

Следующий из ответа Барри. Он компилируется с помощью gcc, но мне не хватает clang:


template<class... Is>
void foo(Is..., Typelist<>) { /*do the stuff*/ }

template<class... Is, class D0, class... Ds>
void foo(Is... is, Typelist<D0, Ds...> , D0 d0, Ds... ds) {
foo<Is..., decltype(std::declval<Is>()+std::declval<D0>())...>(
is...,
(is+d0)...,
Typelist<Ds...>{},
ds...);
}

template<class... Ds>
void bar(Ds... ds) {
foo<unsigned int>(0u, Typelist<Ds...>{}, ds...);
}

И, наконец, тот, кто работает с gcc (5.4, 6.3) и clang (3.9):

template<class... Us>
struct foo_impl<Typelist<>, Typelist<Us...>>{
auto operator()(Us... us)-> void { /*do the stuff here*/ }
};

template<class T, class... Ts, class... Us>
struct foo_impl<Typelist<T, Ts...>, Typelist<Us...>>{
auto operator()(T t, Ts... ts, Us... us)-> void{
foo_impl<Typelist<Ts...>, Typelist<Us..., Us...>>{}(ts..., us..., (us+t)...);
}
};

template <class... Ts>
void bar(Ts... ts){
foo_impl<Typelist<Ts...>, Typelist<unsigned>>{}(ts..., 0u);
}

Надеюсь, кто-то найдет это полезным.

ответил(а) 2021-01-19T19:18:21+03:00 6 месяцев, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема