Специализация частичного шаблона с несколькими пакетами параметров шаблона
Продолжая мое путешествие в мир вариативных шаблонов, я столкнулся с другой проблемой.
Предполагая следующий класс шаблонов:
template < typename T >
struct foo
{
//default implementation
};
можно частично специализировать его для модификаций шаблонных шаблонов следующим образом:
template < template < typename ... > class T, typename ...Args >
struct foo< T< Args... > >
{
//specialized implementation
};
При этом foo< int >
будет соответствовать реализации по умолчанию и foo< std::tuple< int, char > >
для специализированной реализации.
Однако при использовании нескольких параметров шаблона все усложняется. Например, если у нас есть следующий класс шаблонов
template < typename T, typename U >
struct bar {};
и мы хотим частично специализировать его, как это было сделано для foo
, мы не можем делать
template < template < typename ... > class T, typename ...TArgs,
template < typename ... > class U, typename ...UArgs >
struct bar< T< TArgs... >, U< UArgs... > > {};
//This would correspond to the specialized version with
//T=std::tuple,
//TArgs=int,char
//U=std::tuple,
//UArgs=float
bar< std::tuple< int, char >, std::tuple< float > > b;
Действительно, если я прав, у нас может быть только один пакет параметров шаблона, и он должен быть расположен в конце списка параметров. Я понимаю, почему это необходимо в объявлениях шаблонов, но для определенной частичной специализации шаблона (например, пример выше) это не должно быть проблемой.
Возможно ли достичь частичной специализации шаблонов с несколькими пакетами параметров шаблона?
Изменить: теперь я чувствую себя глупо... код, который я дал выше, компилируется отлично (по крайней мере, с gcc 4.5). Ошибка компиляции у меня была не из-за нескольких пакетов параметров, а из-за их использования в качестве параметров функций-членов. В частичной специализации bar
я попытался определить функцию-член, которая принимает параметры TArgs
и UArgs
:
template < template < typename ... > class T, typename ...TArgs,
template < typename ... > class U, typename ...UArgs >
struct bar< T< TArgs... >, U< UArgs... > >
{
void method( TArgs... targs, UArgs... uargs ) //compile error here
{
}
};
В объявлении функции-члена gcc дает мне ошибку
Пакеты параметров должны быть в конце списка параметров.
Насколько я могу судить, компилятор должен иметь возможность определить правильную функцию-член для данного экземпляра шаблона, например. bar< std::tuple< int, char >, std::tuple< float > >
должен содержать функцию-член void method( int, char, float )
. Я делаю что-то неправильно? Или я пытаюсь сделать что-то, что невозможно? Если это так, есть ли веская причина, почему это невозможно?
Ответы
Ответ 1
Наверное, этот ответ не сразу очистит ваш вопрос,
но следующий код, составленный на ideone (gcc-4.5.1), когда я тестировал.
#include <cstdio>
#include <tuple>
template< class, class > struct S {
S() { puts("primary"); }
};
template<
template< class... > class T, class...TArgs
, template< class... > class U, class...UArgs
>
struct S< T< TArgs... >, U< UArgs... > > {
S() { puts("specialized"); }
};
int main()
{
S< int, int > p; // "primary"
S< std::tuple< int, char >, std::tuple< float > > s; // "specialised"
}
Я не уверен, что этот код строго соответствует, но
насколько я читал N3225 14.5.3, я не мог найти утверждение, в котором упоминается
этот пакет параметров шаблона должен быть последним параметром шаблона.
Edit:
Я перечитал N3225 и нашел следующие утверждения:
8.3.5/4 Если параметр-объявление-предложение заканчивается многоточием или пакет параметров функции (14.5.3), количество аргументов должно быть равно или больше, чем количество параметры, которые не имеют значения по умолчанию аргумент и не функционируют пакетов параметров.
14.8.2.5/10 [Примечание. Пакет параметров функции может выполняться только на конец Параметр-declarationlist (8.3.5). -конец примечание]
Итак, как вы упомянули, пакет параметров функции должен быть последним параметром
к сожалению.
Функция шаблона, не являющаяся шаблоном шаблона класса, является обычной функцией
для этого класса при его создании (полностью специализированном).
Поэтому я хочу, чтобы код в этом вопросе мог быть скомпилирован логически, как
специальный случай.