Как написать шаблон C ++, который принимает каждый класс и шаблон класса? - PullRequest
4 голосов
/ 02 июня 2009

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

Я хотел бы написать шаблон, который может принимать любой конкретный класс или класс шаблона в качестве параметра шаблона. Это может показаться бесполезным, потому что, не зная, является ли переданный в T шаблонным или нет, вы не будете знать, как его использовать. Причина, по которой я этого хочу, заключается в том, что я могу объявить общий шаблон без определения, чтобы пользователи затем специализировались. Поскольку пользователи специализируются на этом, они всегда знают о типе, с которым имеют дело. Но пользователи не могут специализировать шаблон без его предварительного объявления.

Вы можете сделать это:

template<class T>
class myclass;

Но это не сработает, если вы передадите шаблонный T, например, myclass<std::vector> не сработает. Итак, мы попробуем это:

template<class T>
class myclass;

template<template<class> T>
class myclass;

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

template<class T>
void myfunc();

template<template<class> T>
void myfunc();

Сладкий, значит, мы все сделали правильно? Что ж, может быть разное количество параметров, заданных параметру шаблона шаблона, поэтому мы должны принять это во внимание также.

template<class T>
void myfunc();

template<template<class> T>
void myfunc();

template<template<class, class> T>
void myfunc();

template<template<class, class, class> T>
void myfunc();

// etc.

Ужасно, но библиотека препроцессора Boost может сгенерировать этот код для нас (и в C ++ 0x будет добавлена ​​поддержка шаблонов с переменными значениями, так что это уродство только временно). Но мы все еще забыли случай! Что если один из параметров T не является классом, а является постоянным целым числом? Давайте попробуем поддержать это:

template<class T>
void myfunc();

template<template<class> T>
void myfunc();

template<template<class, class> T>
void myfunc();

template<template<class, class, class> T>
void myfunc();

// etc.

template<template<class> T>
void myfunc();

template<template<class, int> T>
void myfunc();

template<template<int, class> T>
void myfunc();

template<template<int, class, class> T>
void myfunc();

template<template<class, int, class> T>
void myfunc();

template<template<class, class, int> T>
void myfunc();

// etc.

Э-э-э Учитывая, что любой тип константы может быть передан в шаблон, в любом количестве, смешанный с параметрами класса, комбинаторный взрыв KABLOOEY. Просто, чтобы сделать вещи более сложными, что, если любой из параметров Т сами по себе являются шаблонами?

Ответы [ 3 ]

3 голосов
/ 02 июня 2009

boost :: mpl делает что-то подобное (вот их идея связывания аргумента ). Тем не менее, вы должны сделать много предположений, чтобы заставить его работать, например, используя;

template <class T> foo { }; typedef foo< int_<4> > my_foo_4;

вместо

template <int T> foo { }; typedef foo<4> my_foo_4;

чтобы не предлагать перегрузки для всех комбинаций int, char, bool и т. Д.

Я не могу придумать ничего, что было бы более эффективным, чем подход boost :: mpl, и в целом, я думаю, что любой подход перенесет много проблем; шаблон класса НЕ является типом, и он не может быть таким образом встроен в систему типов (boost :: mpl рассматривает его как функцию для создания новых типов; в более общем смысле он используется для создания «мета-функции») , Я даже не уверен, будут ли шаблоны с переменными параметрами влиять на параметры шаблона (хотя интересный вопрос).

1 голос
/ 02 июня 2009

Решение: используйте перегрузку функций, а не специализацию шаблонов! Время компиляции будет лучше, ограничения исчезли ...

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

template <class T>
int f(const T& t)
{
  return g(t);
} 

int g(int a)
{
  return a+1;
}

int main()
{
   return f(5);
}

Как видите, он работает, хотя функция g определена после f. Это означает, что вы можете определить любой шаблон, который вы хотите, который использует функцию, при условии, что пользователь определяет функцию до того, как использует шаблон, у вас все в порядке, C ++ найдет его.

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

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

0 голосов
/ 02 июня 2009
template <class T> class myclass;

template <> class myclass<int>{};
template <> class myclass<std::vector<int>>{};
template <> class myclass<std::vector<std::vector<int> > >{};

Это то, что вы хотите?

...