повторное связывание шаблона или позднее связывание шаблона или как вызвать копирование шаблона в типе

Часто концептуально шаблон должен быть передан как введите аргумент и компилятор жалуется, потому что это не разрешено 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;
}

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

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

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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]