Почему в шаблоне remove_const отбрасывается константность?

Рейтинг: 0Ответов: 2Опубликовано: 26.07.2023

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

#include <iostream>

template<typename T>
struct type_is {
    using type = T;
};

template<typename T>
struct remove_const : type_is<T> {

};

template<typename T>
struct remove_const<const T> : type_is<T> {

};

template<typename U, typename V>
constexpr bool same = std::is_same_v<U, V>;

int main(int argc, char **argv)
{
    static_assert(same<remove_const<const int>::type, int>);

    return 0;
}

Как я понимаю, наследование используется для того, чтобы повторно не определять поле type. А какие правила выведения типов используются в декларации using type = T? Я сначала думал, что здесь отбрасывается константность, ссылочность и волатайлность, но оказалось, что это не так. Это псевдоним типа и константность здесь не отбрасывается. Каким образом поле type в специализации шаблона remove_const для const T отбрасывает константность? Почему она отбрасывается?

Ответы

▲ 1Принят

Имеются

template<typename T> struct remove_const : type_is<T> {};
template<typename T> struct remove_const<const T> : type_is<T> {};

Рассмотрим на примере

remove_const<mytype>::type

Компилятор смотрит на оба варианта, видит, что для второго варианта он вообще не проходит, остается первый

template<typename T> struct remove_const : type_is<T> {};

в котором T === mytype. Значит,

remove_const<mytype>::type

превращается в T, т.е. просто mytype.

Теперь пусть у нас

remove_const<const mytype>::type

Компилятор смотрит на оба варианта, видит, что для первого варианта все работает при T === const mytype, а для второго при T === mytype. При этом второй вариант "более подходящий" (чтобы точно разобраться, почему и как — см. стандарт), так что выбирается он, с (tot раз напомню) T === mytype.

template<typename T> struct remove_const : type_is<T> {};

в котором T === mytype. Значит,

remove_const<const mytype>::type

как и ранее превращается просто в T,т.е. в mytype.

Так понятнее?

▲ 1

Все проясняется, если давать параметрам осмысленные имена. А не поступать, как товарищ: введите сюда описание изображения

В таком объявлении шаблона понятно, что параметром шаблона может быть тип с const квалификатором или без него.

template<typename TypeMaybeWithConst>
struct remove_const : type_is<TypeMaybeWithConst>
{};

Далее, при объявлении специализации понятно, что параметром специализации может быть просто тип, без квалификатора. При этом параметр шаблона указывается в угловых скобках после имени шаблона, как при инстанцировании. Т.е. параметром шаблона TypeMaybeWithConst тут будет const JustType

template<typename JustType>
struct remove_const<const JustType> : type_is<JustType>
{};

Далее, при инстанцировании шаблона remove_const<const int> параметром шаблона TypeMaybeWithConst будет тип const int, а когда компилятор начнет выбирать подходящую специализацию, он попробует сопоставить параметр шаблона const JustType с фактическим параметром шаблона const int и после успешного сопоставления выведет параметр специализации JustType как int.