23 General utilities library [utilities]

23.15 Metaprogramming and type traits [meta]

23.15.7 Transformations between types [meta.trans]

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

Каждый из шаблонов в данном подразделе должны быть TransformationTrait.

23.15.7.1 Const-volatile modifications [meta.trans.cv]

Таблица45 - Постоянно изменчивые модификации
ШаблонКомментарии
template <class T>
struct remove_­const;
Элемент typedef именуетtype тот же тип,T за исключением того, что любой константный квалификатор верхнего уровня был удален. [ Example:remove_­const_­t<const volatile int> оцениваетсяvolatile intкак, тогда какremove_­const_­t<const int*> оценивается какconst int*. ] end example
template <class T>
struct remove_­volatile;
Элемент typedef именуетtype тот же тип,T за исключением того, что все квалификаторы volatile верхнего уровня были удалены. [ Example:remove_­volatile_­t<const volatile int> оцениваетсяconst intкак, тогда какremove_­volatile_­t<volatile int*> оценивается какvolatile int*. ] end example
template <class T>
struct remove_­cv;
Элемент typedeftype должен быть таким же, какT за исключением того, что любой квалификатор cv верхнего уровня был удален. [ Example:remove_­cv_­t<const volatile int> оцениваетсяintкак, тогда какremove_­cv_­t<const volatile int*> оценивается какconst volatile int*. ] end example
template <class T>
struct add_­const;
ЕслиT это ссылка, функция или тип верхнего уровня с указанием const, тогдаtype именуется тот же тип, что иT, в противном случае T const.
template <class T>
struct add_­volatile;
ЕслиT является ссылкой, функцией или типом верхнего уровня, квалифицированным с указанием изменчивости, тогдаtype именуется тот же тип, что иT, в противном случае T volatile.
template <class T>
struct add_­cv;
Элемент typedeftype называет тот же тип, что и add_­const_­t<add_­volatile_­t<T>>.

23.15.7.2 Reference modifications [meta.trans.ref]

Таблица46 - Справочные модификации
ШаблонКомментарии
template <class T>
struct remove_­reference;
ЕслиT имеет тип «ссылка наT1», тогдаtype имена typedef членаT1; в противном случае -type именаT.
template <class T>
struct add_­lvalue_­reference;
ЕслиT имена a,referenceable type то член typedeftype namesT&; в противном случае -type именаT. [ Note: Это правило отражает семантику свертывания ссылок ([dcl.ref]). ]end note
template <class T>
struct add_­rvalue_­reference;
ЕслиT именует Referenceable типа , то члены ЬурейеГоtype именT&&; в противном случае -type именаT. [ Note: Это правило отражает семантику свертывания ссылок ([dcl.ref]). Например, когда типT называет типT1&, этот тип add_­rvalue_­reference_­t<T> не является ссылкой rvalue. ] end note

23.15.7.3 Sign modifications [meta.trans.sign]

Таблица47 - Модификации знаков
ШаблонКомментарии
template <class T>
struct make_­signed;
ЕслиT именует a (возможно, cv-квалифицированным), signed integer type тогда typedef члена type называет типT; в противном случае, еслиT именуется (возможно, cv-квалифицированный) беззнаковый целочисленный тип, тогдаtype именуется соответствующий знаковый целочисленный тип с теми же cv-квалификаторами, что иT; в противном случае,type именует знаковое целое типа с ,smallest rank для которых sizeof(T) == sizeof(type), с тем же CV-определителями какT.
Requires:T должен быть (возможно, cv-квалифицированным) целочисленным типом или перечислением, но неbool типом.
template <class T>
struct make_­unsigned;
ЕслиT именует a (возможно, cv-квалифицированным), unsigned integer type тогда typedef члена type называет типT; в противном случае, еслиT именуется (возможно, cv-квалифицированный) целочисленный тип со знаком, тогдаtype именуется соответствующий беззнаковый целочисленный тип с теми же cv-квалификаторами, что иT; в противном случае,type называют целое число без знака типа с ,smallest rank для которого sizeof(T) == sizeof(type), с тем же CV-классификаторами какT.
Requires:T должен быть (возможно, cv-квалифицированным) целочисленным типом или перечислением, но неbool типом.

23.15.7.4 Array modifications [meta.trans.arr]

Таблица48 - Модификации массива
ШаблонКомментарии
template <class T>
struct remove_­extent;
ЕслиT тип именуется «массив изU», то в противном случаеtype должен быть член typedef . [ Для многомерных массивов удаляется только первое измерение массива. Для типа «массив » результирующий тип будет . ] UTNote: const Uconst Uend note
template <class T>
struct remove_­all_­extents;
ЕслиT это «многомерный массив изU», результирующий typedef членаtype будетU, в противном случаеT.

[Example:

// the following assertions hold:
assert((is_same_v<remove_extent_t<int>, int>));
assert((is_same_v<remove_extent_t<int[2]>, int>));
assert((is_same_v<remove_extent_t<int[2][3]>, int[3]>));
assert((is_same_v<remove_extent_t<int[][3]>, int[3]>));

end example]

[Example:

// the following assertions hold:
assert((is_same_v<remove_all_extents_t<int>, int>));
assert((is_same_v<remove_all_extents_t<int[2]>, int>));
assert((is_same_v<remove_all_extents_t<int[2][3]>, int>));
assert((is_same_v<remove_all_extents_t<int[][3]>, int>));

end example]

23.15.7.5 Pointer modifications [meta.trans.ptr]

Таблица49 - Модификации указателя
ШаблонКомментарии
template <class T>
struct remove_­pointer;
ЕслиT имеет тип «(возможно , резюме квалифицированное) указательT1» затем член ЬурейеГоtype именT1; в противном случае это именаT.
template <class T>
struct add_­pointer;
ЕслиT называет типreferenceable type или cvvoid тип, то член typedeftype называет тот же тип, что и remove_­reference_­t<T>*; в противном случае -type именаT.

23.15.7.6 Other transformations [meta.trans.other]

Таблица50 - Прочие преобразования
ШаблонКомментарии
template <size_­t Len,
size_­t Align
= default-alignment>
struct aligned_­storage;
Значениеdefault-alignment должно быть наиболее строгим требованием к выравниванию для любого типа объекта C ++, размер которого не превышаетLen ([basic.types]). Член typedeftype должен быть типом POD, подходящим для использования в качестве неинициализированного хранилища для любого объекта, размер которого не больше,Len а выравнивание является делителемAlign.
Requires:Len не должно быть нулевым.Align должен быть равен alignof(T) для некоторого типаT или todefault-alignment.
template <size_­t Len,
class... Types>
struct aligned_­union;
Элемент typedeftype должен быть типом POD, подходящим для использования в качестве неинициализированного хранилища для любого объекта, тип которого указан вTypes; его размер должен быть не менееLen. Статический членalignment_­value должен быть интегральной константой типаsize_­t , значение которого является самым строгим выравниванием из всех типов, перечисленных вTypes.
Requires: Предусмотрен хотя бы один тип.
template <class T>
struct decay;
ПустьU будетremove_­reference_­t<T>. Еслиis_­array_­v<U> есть true, то член typedeftype должен быть равен remove_­extent_­t<U>*. Еслиis_­function_­v<U> естьtrue, то член typedeftype должен быть равенadd_­pointer_­t<U>. В противном случае typedef членаtype равенremove_­cv_­t<U>. [ Note: Это поведение похоже наlvalue-to-rvalue, array-to-pointerиfunction-to-pointer преобразование применяется , когда выражение - значения используется в качестве RValue, но и полоскаcv-qualifiers от типов классов , с тем чтобы более точно моделями по значению передачи аргументов. ] end note
template <bool B, class T = void>struct enable_­if; ЕслиB естьtrue, то член typedeftype должен быть равенT; в противном случае член не должен быть type.
template <bool B, class T, class F>
struct conditional;
ЕслиB естьtrue, то член typedeftype должен быть равенT. ЕслиB естьfalse, то член typedeftype должен быть равенF.
template <class... T>struct common_­type; Если этот признак не является специализированным (как указано в примечании B ниже), членtype должен быть определен или опущен, как указано в примечании A ниже. Если он опущен, член не должен бытьtype. Каждый тип в пакете параметровT должен быть полнымcvvoidили массивом с неизвестными границами.
template <class T>
struct underlying_­type;
Элемент typedeftype называет базовый типT.
Requires:T должен быть полнымenumeration type
template <class Fn,
class... ArgTypes>
struct invoke_­result;
Если выражениеINVOKE(declval<Fn>(), declval<ArgTypes>()...) правильно сформировано при обработке как выражениеunevaluated operand, typedef членаtype называет тип decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...)); в противном случае член не должен бытьtype. Проверка доступа выполняется, как если бы в контексте, не связанном сFn и ArgTypes. Учитывается только действительность непосредственного контекста выражения. [ Note: Компиляция выражения может привести к побочным эффектам, таким как создание экземпляров специализаций шаблонов классов и специализаций шаблонов функций, создание неявно определенных функций и т. Д. Такие побочные эффекты не относятся к «непосредственному контексту» и могут привести к неправильному формированию программы. ] и все типы в пакете параметров должны быть полными типами или массивами с неизвестной границей.end note
Requires:Fn ArgTypes cvvoid

[ Note: Типичная реализация определяется aligned_­storageкак:

template <size_t Len, size_t Alignment>
struct aligned_storage {
  typedef struct {
    alignas(Alignment) unsigned char __data[Len];
  } type;
};

end note]

Это определяется реализация любого ли extended alignment поддерживаются.

Примечание A: Для common_­typeпризнака, применяемого к пакету параметровT типов, членtype должен быть либо определен, либо отсутствовать следующим образом:

  • Еслиsizeof...(T) равно нулю, не должно быть никакого членаtype.

  • Еслиsizeof...(T) это один, пустьT0 обозначает единственный тип, составляющий пачкуT. Член typedef-nametype должен обозначать тот же тип, если таковой имеется, что иcommon_­type_­t<T0, T0>; в противном случае член не будетtype.

  • Еслиsizeof...(T) равно двум, пусть первый и второй составляющие типыT обозначаются символамиT1 иT2, соответственно, и пустьD1 иD2 обозначают те же типы, чтоdecay_­t<T1> и иdecay_­t<T2>, соответственно.

    • Еслиis_­same_­v<T1, D1> естьfalse или is_­same_­v<T2, D2> естьfalse, пустьC обозначает тот же тип, если есть, какcommon_­type_­t<D1, D2>.

    • В противном случае позвольтеC обозначить тот же тип, если таковой имеется, как

      decay_t<decltype(false ? declval<D1>() : declval<D2>())>

      [ Note: Это не будет применяться, если есть специализацияcommon_­type<D1, D2>. ] end note

    В любом случае член typedef-nametype должен обозначать тот же тип, если таковой имеется, какC. В противном случае член не будетtype.

  • Еслиsizeof...(T) больше двух, пустьT1,T2иR, соответственно, обозначают первый, второй и (пакет) остальных составляющих типовT. ПозвольтеC обозначить тот же тип, если таковой имеется, какcommon_­type_­t<T1, T2>. Если есть такой типC, член typedef-nametype должен обозначать тот же тип, если таковой имеется, какcommon_­type_­t<C, R...>. В противном случае член не будетtype.

Примечание Б. Несмотря на положения[meta.type.synop]и в соответствии с ними[namespace.std], программа может специализироватьсяcommon_­type<T1, T2> на типахT1 иT2 таких, которые is_­same_­v<T1, decay_­t<T1>> и is_­same_­v<T2, decay_­t<T2>> являются каждым из нихtrue. [ Note: Такие специализации необходимы, когда требуются только явные преобразования между аргументами шаблона. ] У такой специализации не обязательно должен быть член с именем , но если он есть, этот член должен быть доступным и однозначным cv-unqualified не ссылочным типом, в который каждый из типов и может быть явно преобразован. Кроме того, будет обозначать тот же тип, если таковой имеется . Нарушение правил данной заметки не требует диагностики.end notetypetypedef-nameCT1 T2 common_­type_­t<T1, T2> common_­type_­t<T2, T1>

[ Example: Учитывая эти определения:

using PF1 = bool  (&)();
using PF2 = short (*)(long);

struct S {
  operator PF2() const;
  double operator()(char, int&);
  void fn(long) const;
  char data;
};

using PMF = void (S::*)(long) const;
using PMD = char  S::*;

справедливы следующие утверждения:

static_assert(is_same_v<invoke_result_t<S, int>, short>);
static_assert(is_same_v<invoke_result_t<S&, unsigned char, int&>, double>);
static_assert(is_same_v<invoke_result_t<PF1>, bool>);
static_assert(is_same_v<invoke_result_t<PMF, unique_ptr<S>, int>, void>);
static_assert(is_same_v<invoke_result_t<PMD, S>, char&&>);
static_assert(is_same_v<invoke_result_t<PMD, const S*>, const char&>);

end example]