Специализация шаблона с аргументом по умолчанию

У меня есть программа, которая заключается в следующем. Есть базовый шаблон struct X и частичная специализация с SFINAE.

template <typename T, typename U = void>
struct X{
  X() {
    std::cout << "in 1" << std::endl;
  };
};

template <typename T>
struct X< T, std::enable_if_t<std::is_integral_v<T>> > {
  X() {
    std::cout << "in 2" << std::endl;
  };
};

int main() {
  X<int> x;
}

При запуске программы in 2 печатается.

  1. Почему вторая специализация выбрана первой, так как они фактически объявляют struct X<int, void>, Что делает std::enable_if_t<std::is_integral_v<T>> более специализированный, чем аргумент типа шаблона по умолчанию, как показано в базовом шаблоне?

  2. Почему аргумент типа по умолчанию базового шаблона должен совпадать с типом, определенным частичной специализацией для вызываемой частичной специализации, и in 2 быть напечатанным. Почему меняется на std::enable_if_t<std::is_integral_v<T>, bool> вызвать базовый шаблон in 1 быть названным?

2 ответа

Решение

Ответы на ваши вопросы находятся в шаблоне частичного заказа. Это механизм, который компилятор использует для определения того, какой шаблон лучше всего подходит (будь то перегрузка шаблона функции или, в вашем случае, специализация шаблона класса).

Вкратце, ваша реализация шаблона имеет 2 параметра T а также Uв то время как ваша специализация SFINAE имеет только T параметр, а второй выводится из T, Поэтому он более специализирован, чем общий случай, и в конце концов, когда вы ссылаетесь на X<int, void>, специализация выбрана.

Теперь вопрос 2. Предположим, мы заменим enable_if параметр с bool вместо void, Теперь наша специализация будет X<int, bool> вместо X<int, void>поэтому, когда вы ссылаетесь на X<int>т.е. X<int, void>больше не соответствует специализации, потому что это 2 разных типа.

1) [...] Что делает std::enable_if_t> более специализированным, чем аргумент типа шаблона по умолчанию, как показано в базовом шаблоне?

Итак, знаете ли вы, что, если два шаблона совпадают, выбирается более специализированный.

Ну... второй более специализированный, потому что если X соответствует специализации (так что если X является целочисленным типом), это также соответствует общей версии.

Но существуют пары типов (например: std::string, void), которая соответствует универсальной версии и не соответствует специализации.

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

Почему аргумент типа по умолчанию базового шаблона должен совпадать с типом, определенным частичной специализацией для частичной специализации, которая будет вызвана и в 2 должна быть напечатана. Почему изменение на std::enable_if_t, bool> вызывает базовый шаблон в 1 для вызова?

Вы должны понять, как работает прием значения по умолчанию.

У вас есть это общая версия, которая

template <typename T, typename U = void>
struct X;

так что писать X<int> xпишешь X<int, void> x; и обязательно соответствует универсальной версии.

Специализация

template <typename T>
struct X< T, std::enable_if_t<std::is_integral_v<T>>>;

Вопрос: X<int, void> Матчи X< T, std::enable_if_t<std::is_integral_v<T>>>?

Ответ: да, потому что int является интегральным, так std::enable_if_t<std::is_integral_v<T>> замещен void,

Предположим теперь, что общая специализация становится

template <typename T>
struct X< T, std::enable_if_t<std::is_integral_v<T>, bool>>

У нас есть это X<int> x опять X<int, void> x и соответствует снова универсальной версии.

Вопрос: X<int, void> соответствует также X< T, std::enable_if_t<std::is_integral_v<T>, bool>>?

Ответ: нет, потому что std::enable_if_t<std::is_integral_v<T>, bool> становиться bool а также X<int, void> не соответствует X<int, bool>

Таким образом, общая версия является единственной, которая соответствует и выбрана.

Другие вопросы по тегам