Псевдоним шаблона специализации - PullRequest
30 голосов
/ 08 июля 2011

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

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

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

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

Ответы [ 4 ]

26 голосов
/ 08 июля 2011

Стандарт подразумевает под "специализацией" преобразование универсального шаблона в более специализированную сущность. Например, создание экземпляра шаблона класса, не являющегося членом, дает класс, который больше не является шаблоном. Термин «специализация» имеет два аспекта и может относиться к сгенерированной специализации (которая представляет собой конкретизированную специализацию, возможно, из частичной специализации) и к явной специализации (на которую вы ссылались).

Шаблоны псевдонимов не создаются и их специализации не существует. Там нет ничего, что они могли бы создать экземпляр. Вместо этого, когда за их именем следует список аргументов шаблона, обозначаемый тип является типом, который вы получаете, заменяя список имен и аргументов на тип псевдонима, заменяя все ссылки на параметры шаблона аргументами, указанными в списке аргументов. То есть, вместо специализации псевдонима, сам шаблон псевдонима служит псевдонимом, без необходимости что-либо создавать. Эта замена сделана очень рано. Рассмотрим:

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, «Предлагаемое дополнение к C ++: Шаблоны Typedef» , раздел 2.2

2.2 Основной выбор: специализация против всего остального

После обсуждения отражателей и в Evolution WG выясняется, что нам нужно выбирать между двумя взаимоисключающими моделями:

  1. Шаблон typedef сам по себе не является псевдонимом; только (возможно, специализированные) экземпляры шаблона typedef являются псевдонимами. Этот выбор позволяет нам иметь специализацию шаблонов typedef.

  2. Шаблон typedef сам по себе является псевдонимом; это не может быть специализированным. Этот выбор позволит:

    • вычет на параметры функции шаблона typedef (см. 2.4)
    • объявление, выраженное с использованием шаблонов typedef, должно быть таким же, как объявление без шаблоны typedef (см. 2.5)
    • Шаблоны typedef для соответствия параметрам шаблона (см. 2.6)

Следует отметить, что цитируемая статья, которая поддерживает вариант 1, не попала в C ++ 0x.


РЕДАКТИРОВАТЬ: Потому что вы отчаянно хотите, чтобы в спецификации цитата говорила так явно. 14.5p3 это тот, который делает

Поскольку объявление псевдонима не может объявить идентификатор шаблона, невозможно частично или явно специализировать шаблон псевдонима.

7 голосов
/ 08 июля 2011

Бьярне говорит :

Специализация работает (вы можете псевдоним набор специализаций, но вы не можете специализировать псевдоним)

И, покане явное правило, «шаблоны псевдонимов» отсутствуют в следующем списке в 14.7.3 / 1:

Явная специализация любого из следующего:

  • функцияtemplate
  • шаблон класса
  • функция-член шаблона класса
  • статический член данных шаблона класса
  • класс-член шаблона класса
  • шаблон класса члена класса или шаблона класса
  • шаблон функции члена класса или шаблона класса

может быть объявлен [...]

Я думаю, что это лучшая гарантия, которую вы получите.

4 голосов
/ 27 декабря 2012

Я не уверен, что понимаю вопрос, но в любом случае я пытался смоделировать специализацию шаблона псевдонима.

Я предполагаю, что идея состоит в том, чтобы ограничить шаблон псевдонима определенным типом (сопоставленным с шаблоном);что-то, что мы использовали для такого рода кода:

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;
}

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

Улучшения приветствуются.

3 голосов
/ 12 апреля 2018

Если вам нужно поточечное сопоставление чего-либо с типами, это работает (в gcc 4.8.3):

//  int to type mapper
template<int BITS>
struct BitsToTypesMap
{
    typedef void TYPE;  //  default
};

//  pointwise mapping 
template<>
struct BitsToTypesMap<32>{  typedef int TYPE;   };
template<>
struct BitsToTypesMap<8>{   typedef char TYPE;  };
template<>
struct BitsToTypesMap<16>{  typedef short TYPE; };

//  cute wrapping
template<int BITS> using MyScalarType = typename BitsToTypesMap<BITS>::TYPE;

//  TEST
template<int BITS>
MyScalarType<BITS>
Add ( MyScalarType<BITS> x, MyScalarType<BITS> y )
{
    return x+y;
}

int
test()
{
    MyScalarType<32> i=Add<32>(1,2);
    MyScalarType<8 > b=Add<8 >(1,2);
    MyScalarType<16> s=Add<16>(1,2);
    return i+b+s;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...