Специализация шаблонов псевдонимов
Могут ли шаблоны псевдонимов (14.5.7) быть явно специализированными (14.7.3)?
Мой стандарт-fu меня не устраивает, и я не могу найти компилятор для тестирования.
Текст "когда идентификатор шаблона ссылается на специализацию шаблона псевдонимов" подразумевает "да", но затем, как представляется, этот пример ссылается на что-то другое, подразумевая, что нет.
NB. Я работаю из n3242, один позади FDIS, в котором заголовок этого раздела является "Шаблоны псевдонимов". Лол.Суб >
Ответы
Ответ 1
То, что Стандарт означает "специализация", - это преобразование общего шаблона в более специализированный объект. Например, создание экземпляра класса, не являющегося членом класса, дает класс, который не является шаблоном. Термин "специализация" имеет два раза и может ссылаться на сгенерированную специализацию (которая является специализацией, которая была создана, возможно, из частичной специализации) и явной специализации (о чем вы говорили).
Шаблоны псевдонимов не создаются и не имеют специализации. Ничто не может создать. Вместо этого, когда за их именем следует список аргументов шаблона, обозначаемый тип - это тип, который вы получаете, заменяя имя и список аргументов типом alias'ed, заменяя все ссылки на параметры шаблона аргументами, приведенными в списке аргументов. То есть, вместо того, чтобы специализироваться на том, что он является псевдонимом, сам шаблон псевдонимов служит псевдонимом, без необходимости создавать что-либо. Эта замена выполняется очень рано. Рассмотрим:
template<typename T> using ref = T&;
template<typename T> void f(ref<T> x) { x = 10; }
int main() { int a; f(a); return a; /* 10 */ }
Замена выполняется в момент имени ref<T>
(такие имена используются для обозначения специализированных функций класса или функции, поэтому спецификация описывает такие имена для "ссылки на специализацию шаблона псевдонимов" ). То есть параметр f
имеет тип T&
, и, таким образом, можно вывести T
. Это свойство предотвращает явные или частичные специализации шаблонов псевдонимов. Потому что для того, чтобы выбрать правильную специализацию ref
, нужно знать T
. Но чтобы узнать это, нужно сравнить ref<T>
с типом аргумента, чтобы вывести T
. Он обобщен в статье N1406, "Предлагаемое дополнение к С++: Шаблоны Typedef" , раздел 2.2
2.2 Основной выбор: специализация против всего остального
После обсуждения рефлекторов и рабочей группы Evolution выясняется, что мы должны выбирать между двумя взаимоисключающими моделями:
-
Шаблон typedef сам по себе не является псевдонимом; только (возможно, специализированные) экземпляры шаблона typedef являются псевдонимами. Этот выбор позволяет нам специализироваться на шаблонах typedef.
-
Шаблон typedef сам по себе является псевдонимом; он не может быть специализированным. Этот выбор позволил бы:
- вывод по параметрам функции шаблона typedef (см. 2.4)
- декларация, выраженная с использованием шаблонов typedef, будет такой же, как декларация без Шаблоны typedef (см. 2.5)
- typedef шаблоны для соответствия параметрам шаблона шаблона (см. 2.6)
Следует отметить, что цитированная статья, которая поддерживает вариант 1, не попала в С++ 0x.
РЕДАКТИРОВАТЬ: Потому что вы отчаянно хотите иметь цитату с предложением так явно. 14.5p3 - это тот, который делает
Поскольку декларация alias не может объявить идентификатор шаблона, невозможно частично или явно специализировать шаблон псевдонима.
Ответ 2
Bjarne говорит:
Специализация работает (вы можете использовать набор специализаций, но вы не можете специализировать псевдоним)
И, хотя не явное правило, в следующем списке отсутствуют "шаблоны псевдонимов" в 14.7.3/1:
Явная специализация любого из следующего:
- шаблон функции
- шаблон класса
- функция-член шаблона класса
- статический элемент данных шаблона класса
- класс-член шаблона класса
- шаблон класса участника шаблона класса или класса
- шаблон функции-члена шаблона класса или класса
может быть объявлен [...]
Я думаю, что это лучшая гарантия, которую вы получите.
Ответ 3
Я не уверен, понимаю ли я этот вопрос, но в любом случае я попытался имитировать специализацию шаблона псевдонимов.
Я предполагаю, что идея состоит в том, чтобы ограничить шаблон псевдонима определенным (тип с сопоставлением с образцом); то, что мы привыкли делать с таким типом кода:
template<class Vector> struct old_style;
template<class T> struct old_style<std::vector<T> >{
typedef typename std::vector<T>::value_type type;
};
(это просто пример, есть другой способ извлечь value_type
общего std::vector
).
Теперь к псевдонимам:
template<class Vector> using new_style = typename Vector::value_type;
Он выполняет ту же работу, но это не заменяет old_stype<...>::type
, так как оно не является ограничительным. Первая попытка иметь идеальную замену псевдонимов - это гипотетический код:
//template<class Vector> using new_style2; // error already here
//template<class T> using new_style2<std::vector<T> > = typename Vector::value_type;
К сожалению, он не компилируется (теоретически из-за номинальных причин, изложенных в других ответах и стандарте, на практике, я думаю, нет основополагающих причин для этого ограничения). К счастью, можно отбросить старомодный способ struct::type
сделать это только с использованием новой функции шаблона псевдонимов для пересылки работы,
template<class Vector> struct new_style2_aux;
template<class T> struct new_style2_aux<std::vector<T> >{
typedef typename std::vector<T>::value_type type;
};
template<class Vector> using new_style2 = typename new_style2_aux<Vector>::type;
Можно сделать это автоматически с помощью define
#define SPECIALIZED_ALIAS_TEMPLATE(NamE, Pattern_arG, PatterN_expR, DefinitioN) \
template<class> struct NamE ## _aux; \
template<Pattern_arG> struct NamE ## _aux<PatterN_expR>{ \
typedef DefinitioN type; \
}; \
template<class NamE ## _dummy> using NamE = typename NamE ## _aux< NamE ## _dummy >::type;
который может использоваться как:
SPECIALIZED_ALIAS_TEMPLATE(new_style3, class T, std::vector<T>, typename std::vector<T>::value_type);
Если требуется произвольное число специализаций (или не локально в коде), нужно использовать более сложный define
в двух частях: один для объявления и один для специализации (как и должно быть):
#define DECLARE_ALIAS_TEMPLATE(NamE)\
template<class> struct NamE ## _aux;\
template<class NamE ## _dummy> using NamE = typename NamE ## _aux< NamE ## _dummy >::type;
#define SPECIALIZE_ALIAS_TEMPLATE(NamE, Pattern_arG, PatterN_expR, DefinitioN)\
template<Pattern_arG> struct NamE ## _aux<PatterN_expR>{ \
typedef DefinitioN type; \
};
Используется следующим образом:
DECLARE_ALIAS_TEMPLATE(new_style4);
SPECIALIZE_ALIAS_TEMPLATE(new_style4, class T, std::vector<T>, typename std::vector<T>::value_type);
SPECIALIZE_ALIAS_TEMPLATE(new_style4, class T, std::set<T>, typename std::set<T>::value_type);
Все приведенные выше коды можно скопировать и вставить для проверки:
#include<vector>
#include<map>
// ... paste code above //
int main(){
old_style<std::vector<double> >::type a; // is a double
// old_style<std::set<double> >::type a; // error (should work only for std::vector)
new_style2<std::vector<double> > b; // is double
// new_style2<std::set<double> > c; // error (should work only for std::vector)
new_style3<std::vector<double> > d; // is double
// new_style3<std::set<double> > d; // error (should work only for std::vector)
new_style4<std::vector<double> > e; // is double
new_style4<std::set<double> > f; // is double, this is another specialization
return 0;
}
Извините, если это не то, что вы ищете. Я считаю, что он может использоваться с вариационными шаблонами и с дополнительными аргументами шаблона (по специализации), но не проверял его.
Усовершенствования приветствуются.