Подтвердить что ты не робот

Специализация шаблонов псевдонимов

Могут ли шаблоны псевдонимов (14.5.7) быть явно специализированными (14.7.3)?

Мой стандарт-fu меня не устраивает, и я не могу найти компилятор для тестирования.

Текст "когда идентификатор шаблона ссылается на специализацию шаблона псевдонимов" подразумевает "да", но затем, как представляется, этот пример ссылается на что-то другое, подразумевая, что нет.

NB. Я работаю из n3242, один позади FDIS, в котором заголовок этого раздела является "Шаблоны псевдонимов". Лол.Суб >

4b9b3361

Ответ 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;
}

Извините, если это не то, что вы ищете. Я считаю, что он может использоваться с вариационными шаблонами и с дополнительными аргументами шаблона (по специализации), но не проверял его.

Усовершенствования приветствуются.