2

Вот проблема, с которой я столкнулся во время игры с вариативными шаблонами. У меня есть некоторый код, который использует специализацию для подсчета «интересных» типов в параметрах пакета, как так:специализация вариативных шаблонов с шаблонами классов

template<typename... _Pp> 
struct count; 

template<> 
struct count<> 
{ 
    static const int value = 0; 
}; 

// ignore uninteresting types 
template<typename _First, typename... _Rest> 
struct count<_First, _Rest...> 
{ 
    static const int value = count<_Rest...>::value; 
}; 

// add 1 for a pointer 
template<typename _First, typename... _Rest> 
struct count<_First*, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
}; 

// add 1 for a reference 
template<typename _First, typename... _Rest> 
struct count<_First&, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
}; 

// add 1 for an int 
template<typename... _Rest> 
struct count<int, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
}; 

Этот код работает отлично, но я бег в проблемы, если я хочу использовать тот же подход для подсчета шаблонов классов:

// add 1 for a vector 
template<typename... _Rest> 
struct count<vector, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
}; 

выше код не компилировать, ошибка «ожидается тип, получил„вектор“» на строку, начинающуюся с «подсчета STRUCT». Я также не в состоянии что-нибудь попроще, все шаблоны классов, принимающие один аргумент:

// add 1 for a class template with 1 type parameter 
template<template<typename> class _First, typename... _Rest> 
struct count<_First, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
} 

Этот код также не компилировать, жалуясь на «ожидается типа, получил" _First»в очередной раз на линии, начиная с "struct count". Кто-нибудь знает способ достижения этой цели с использованием этого подхода (т. Е. Некоторые изменения, которые я могу внести в одну или обе специализации, которые заставят их скомпилировать и выполнить требуемый расчет во время компиляции)?

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

// pass a container as a parameter using variadic template-template 

parameter 
template<typename _Tp, template<typename...> class _C> 
struct success 
{ 
    // not specialized for any container 
    static const bool is_specialized = false; 
    // data member of container type 
    _C<_Tp> c_; 
}; 

// partial specialization of above for std::vector 
template<typename _Tp> 
struct success<_Tp, std::vector> 
{ 
    // specialized for vector 
    static const bool is_specialized = true; 
    // again, data member of container type 
    std::vector<_Tp> c_; 
}; 

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

ответ

2

Если я правильно понимаю, что вы хотите ...да, вы можете создать шаблонную структуру, которая может рассчитывать «шаблоны классов», так что вы можете написать что-то вроде

count<std::vector, std::map, std::set, std::pair>::value 

, но вы не можете смешивать шаблоны классов и простые typenames, так что вы не можете написать что-то вроде

count<std::vector, int &, float, std::set>::value 

проблема заключается в том, что если определить

template <typename... _Pp> 
    struct count; 

вы можете передать std::vector<int> к нему, потому что std::vector<int> является typename, но вы не можете пройти std::vector, потому что std::vector не является typename; это template<typename...> class (или шаблон шаблона), что это разные вещи.

Вы можете написать что-то вроде следующего struct countC

template <template<typename...> class ...> 
struct countC; 

template <> 
struct countC<> 
{ static const int value = 0; }; 

// ignore uninteresting templates 
template<template<typename...> class F, template<typename...> class ... R> 
struct countC<F, R...> 
{ static const int value = countC<R...>::value; }; 

template <template<typename...> class ... R> 
struct countC<std::vector, R...> 
{ static const int value = 1 + countC<R...>::value; }; 

Ниже приведен рабочий полный пример, где я переписать свой struct count в struct countT для подсчета выбранных типов, я добавил struct countC графу выбранного " class templates ", и я добавил struct countV для подсчета выбранных значений фиксированного имени.

#include <map> 
#include <set> 
#include <vector> 
#include <utility> 
#include <iostream> 

// countC for templates 

template <template<typename...> class ...> 
struct countC; 

template <> 
struct countC<> 
{ static const int value = 0; }; 

// ignore uninteresting templates 
template<template<typename...> class F, template<typename...> class ... R> 
struct countC<F, R...> 
{ static const int value = countC<R...>::value; }; 

template <template<typename...> class ... R> 
struct countC<std::vector, R...> 
{ static const int value = 1 + countC<R...>::value; }; 

template <template<typename...> class ... R> 
struct countC<std::map, R...> 
{ static const int value = 1 + countC<R...>::value; }; 

template <template<typename...> class ... R> 
struct countC<std::pair, R...> 
{ static const int value = 1 + countC<R...>::value; }; 


// countV for for values of a fixed type 

template <typename T, T ... v> 
struct countV; 

template <typename T> 
struct countV<T> 
{ static const int value = 0; }; 

// ignore uninteresting values 
template <typename T, T f, T ... r> 
struct countV<T, f, r...> 
{ static const int value = countV<T, r...>::value; }; 

// count only int odd values 
template <int f, int ... r> 
struct countV<int, f, r...> 
{ static const int value = (f % 2) + countV<int, r...>::value; }; 


// countT for typenames 

template <typename...> 
struct countT; 

template <> 
struct countT<> 
{ static const int value = 0; }; 

// ignore uninteresting types 
template <typename F, typename ... R> 
struct countT<F, R...> 
{ static const int value = countT<R...>::value; }; 

template <typename F, typename ... R> 
struct countT<F*, R...> 
{ static const int value = 1 + countT<R...>::value; }; 

template<typename F, typename ... R> 
struct countT<F&, R...> 
{ static const int value = 1 + countT<R...>::value; }; 

template<typename ... R> 
struct countT<int, R...> 
{ static const int value = 1 + countT<R...>::value; }; 


int main() 
{ 
    std::cout << "countC vector + map + set + pair     = " 
     << countC<std::vector, std::map, std::set, std::pair>::value 
     << std::endl; 

    std::cout << "countT int + float + bool* + double& + bool + int& = " 
     << countT<int, float, bool*, double&, bool, int&>::value 
     << std::endl; 

    std::cout << "countV int, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = " 
     << countV<int, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value 
     << std::endl; 

    std::cout << "countV long, 1 + 4 + 4 + 5 + 7 + 10 + 11 + 16 + 15 = " 
     << countV<long, 1, 4, 4, 5, 7, 10, 11, 16, 15>::value 
     << std::endl; 

    return 0; 
} 

p.s .: извините за мой плохой английский.

+0

Претензия «но вы не можете смешивать шаблоны классов и простые типы имен», по-видимому, является ключевой проблемой здесь; Я немного посмотрел на рабочий проект N3797, но не могу понять, что такое правила, можете ли вы указать мне больше информации об этом ограничении? –

+0

@BDatRivenhill - Извините: я исправляю себя: вы не можете смешивать шаблоны классов и простые имена в одном и том же параметре шаблона * pack *. Obviouly вы можете смешать создать класс templare, который ожидает одиночные имена типов и один шаблон. Но когда вы создаете пакет параметров, существуют разные производственные правила (если я не ошибаюсь), а пакет параметров может принимать только типы имен ('typename ... Ts') или шаблоны (' template class ... Cs') , – max66

+0

@BDatRivenhill - Укажите мне больше информации об этом ограничении? Я полагаю, что это сомнение вызывает другой вопрос и, извините, но я не очень хорошо разбираюсь в стандарте. Я читаю N3797, который вы назвали, но для меня это слишком сложно. Я полагаю, что могут быть релевантными различные правила производства (14.1) и правило сопоставления в 14.3: (продолжение) – max66

1

Как насчет чего-то подобного?

// add 1 for a vector 
template<typename... _Rest, typename T> 
struct count<vector<T>, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
}; 

И это?

// add 1 for a class template with 1 type parameter 
template<template<typename> class _First, typename T, typename... _Rest> 
struct count<_First<T>, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
}; 
+0

Как и в случае с другим ответом, это связывает первый параметр вектора с каким-либо другим типом в пакете параметров, чего я не хочу. См. Редактирование, добавленное в исходный вопрос. –

1

Оно должно быть:

template<typename... _Rest, typename... T> 
struct count<std::vector<T...>, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
}; 

Generic версия:

template<template<typename...> class C, typename... _Rest, typename... T> 
struct count<C<T...>, _Rest...> 
{ 
    static const int value = 1 + count<_Rest...>::value; 
}; 

VARIADIC вопросы пак.

+0

Это не совсем то, что я хочу сделать из-за введения дополнительного пакета параметров T. Я хочу, чтобы вектор имел свои параметры unbound. См. Редактирование исходного вопроса. –

+0

@BDatRivenhill Что? Класс шаблона не представляет тип, если вы его не специализируете. Из рабочего проекта: шаблон _A определяет семейство классов или функций или псевдоним для семейства типов_. Вы знаете, что 'std :: vector ' и 'std :: vector ' абсолютно разные типы, не так ли? Вы хотите посчитать что-то, для которого действительная специализация может даже существовать? Итак, что вы считаете в этом случае? Специалисты просят тип, извините. – skypjack

+0

Суть в том, почему: специализация «struct success» для std :: vector компилируется и специализация «struct count» для std :: vector не компилируется? Понимание этого поможет мне понять, можно ли достичь моей цели здесь. –

Смежные вопросы