Рекурсия пакета аргументов C ++ с двумя аргументами - PullRequest
4 голосов
/ 06 августа 2020

У меня есть шаблонный класс, который использует два типа:

template<typename T1,typename T2> class Foo { ... };

Мне нужно написать функцию, которая принимает любое количество Foo переменных:

template <typename T1, typename T2, typename... Others> size_t getSize(Foo<T1,T2> *f, Foo<Others>*... o) { ... };

Если я реализую class Foo только с одним параметром шаблона, он работает хорошо. Но с двумя (или более) параметрами компилятор жалуется, что Foo<Others> требует два аргумента.

Возможно ли добиться пересылки пакета аргументов, когда class Foo имеет несколько параметров шаблона?

Ответы [ 2 ]

5 голосов
/ 06 августа 2020

Ваша ошибка - Foo<Others>*... o аргумент. Распаковка этого аргумента для пакета шаблонов A, B, C, D, E даст вам столько o аргументов: Foo<A>, Foo<B>, Foo<C>, ....

На мой взгляд, было бы проще, если бы вы просто объявили свои аргументы как Other и пусть рекурсия завершится неудачно, если в дальнейшем они не будут соответствовать ни одному экземпляру Foo:

template <typename T1, typename T2, typename... Others> size_t getSize(Foo<T1,T2> *f, Others... *o) { ... };

Здесь каждый тип Others в пакете будет выведен на тип, который вы передаете. Если вы вызываете getSize рекурсивно с уменьшенным количеством аргументов, все они в конечном итоге будут сопоставлены с аргументом Foo<T1,T2>:

return f->size() 
     + getSize(std::forward<Others>(o)...); // the first argument in the pack will
                                            // be Foo<T3,T4> type 
                                            // or the compilation will fail

Вы также можете добавить черту типа, чтобы выполнить проверку напрямую:

template <class T> struct IsFoo : std::false_type {};
template <class T, class U> struct IsFoo<Foo<T,U>> : std::true_type {};

template </* ... */>
std::enable_if_t<std::conjunction<IsFoo<Others>::value...>::value, size_t> getSize(/* ... */)
4 голосов
/ 06 августа 2020

А как насчет

template <typename ... Ts1, typename ... Ts2>
std::size_t get_size (Foo<Ts1, Ts2> * ... fs)
 { /* ... */ }

?

Или, может быть,

template <typename T1, typename T2, typename ... Us1, typename ... Us2>
std::size_t get_size (Foo<T1, T2> * f, Foo<Us1, Us2> * ... fs)
 { /* ... */ }

, если вы хотите, чтобы первый Foo управлялся по-другому.

...