Часто концептуально шаблон должен быть передан как введите аргумент и компилятор жалуется, потому что это не разрешено c ++ — по крайней мере, до и включая c ++ 11 (Обновление II: кроме как см. последний пример определения не специализированного шаблона)
Эти понятия часто используются и должны иметь название. Смотрите примеры кода ниже, если не понятно, что я имею в виду.
Моей первой мыслью было, что это тоже можно назвать прохождение неполного типа но это не правильно. Другой пользователь также заявляет, что у него нет слова для этого и свободно называет его поздняя привязка аргументов шаблона. Я думаю, что его терминология хорошо визуализирует концепцию.
Мой вопрос: как правильно назвать идиому, стоящую за этим или соответствующими шаблонами?
ОБНОВИТЬ Керрек предлагает назвать идиому повторное связывание шаблона. Это имя отображает только несколько результатов Google. Тем не менее, я думаю, что это тоже очень хорошее имя, потому что стандартные распределители называют свои связанные внутренние классы снова переплетать.
В следующем примере вы можете настроить, если ваша база данных использует map
или же hashmap
внутренне:
#include <map>
struct map_wrapper
{
template<typename K, typename V>
using type = std::map<K,V>;
};
template<typename storage>
struct my_database
{
typename storage::template type<int, int> x;
typename storage::template type<int, double> y;
};
main ()
{
my_database<map_wrapper> db;
db.x[0] = 1;
db.y[0] = 2.0;
}
Или аналогично
#include <map>
#include <boost/mpl/apply.hpp>
template <typename storage>
struct my_database
{
typename boost::mpl::apply<storage, int>::type x;
typename boost::mpl::apply<storage, double>::type y;
};
int main ()
{
my_database< std::map<int, boost::mpl::_1> > db;
db.x[0] = 1;
db.y[0] = 2.0;
}
Обновление II: К моему смущению я не знал следующего решения, которое просто передает шаблон в качестве аргумента для создания экземпляра шаблона. В этом особом случае допустимо передавать нетип.
#include <map>
#include <unordered_map>
template<template<typename...> class Storage>
struct my_database
{
Storage <long,char> x;
Storage <long,double> y;
};
int main ()
{
my_database< std::map > db1;
db1.x[0] = '1';
db1.y[0] = 2.2;
my_database< std::unordered_map > db2;
db2.x[0] = '1';
db2.y[0] = 2.2;
}
Примеры других способов снова переплетать или же позднее связывание аргументы шаблона, конечно, приветствуются.
Вы предоставили шаблон где тип ожидается.
Для чего это стоит, GCC 4.8 дает достойную диагностику:
template <typename> struct Foo;
template <typename> struct Bar;
int main()
{
Foo<Bar> x;
}
Диагностика:
In function ‘int main()’:
error: type/value mismatch at argument 1 in template parameter list for ‘template<class> struct Foo’
Foo<Bar> x;
^
error: expected a type, got ‘Bar’
(GCC стал намного лучше, так как Clang начал выдавать очень хорошие сообщения об ошибках, так что это может быть недавно; я думаю, что Clang также выдаст здесь полезную ошибку.)
Относительно вашего обновленного вопроса: Типичный способ сделать контейнерный адаптер или вообще класс, который нуждается в определенном контейнере, который вы хотите настроить, состоит в том, чтобы передать весь контейнер как параметр шаблона:
template <typename XContainer, typename YContainer>
struct Database
{
XContainer xstorage;
YContainer ystorage;
};
Database<std::map<int, double>, std::unordered_map<std::string, double>> db;
db.xstorage[1] = 2.5;
db.ystorage["foo"] = 4.5;
Это наиболее общее решение, так как вы можете использовать любой класс, который соответствует вашим потребностям, не требуя, чтобы этот класс имел какую-либо конкретную структуру.
Как альтернатива (который я не рекомендую), если вы хотите, чтобы все ваши контейнеры были шаблонными специализациями одного и того же шаблона, вы можете передать шаблон непосредственно как параметр шаблона (так называемый параметр шаблона шаблона):
template <template <typename, typename, typename...> class CTmpl,
typename XType,
typename YType>
struct Database
{
CTmpl<XType, double> x;
CTmpl<YType, double> y;
};
Database<std::map, int, std::string> db;
// as above
Это намного более ограничительно: теперь ваша база данных должна использовать не только одну и ту же структуру данных для всего, но и структуру данных. имеет быть заданным в качестве шаблона с фиксированными первыми двумя параметрами «тип ключа» и «тип отображения».
Других решений пока нет …