Специализация шаблона на C++ с использованием Enable_if

Как в этом случае работает специализация шаблонов в C++20:

#include <iostream>

template <typename T, typename E> void AFuncToTest() 
{
    std::cout << "it fails!" << std::endl;
}

template <typename T, std::enable_if_t<std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>>> void AFuncToTest()
{
    std::cout << "int value!" << std::endl;
}

int main() 
{
    AFuncToTest<int, int8_t>();
}

ВЫВОД: «не получается!»

Почему код печатает, он терпит неудачу! так как я определил int8_t, например??

AFuncToTest<int, int8_t>(); не соответствует: шаблон <typename T, std::enable_if_t<std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>>> void AFuncToTest()

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

#include <iostream>

template <typename T, typename E> void AFuncToTest() 
{
    std::cout << "it fails!" << std::endl;
}

template <typename T, int8_t> void AFuncToTest()
{
    std::cout << "int value!" << std::endl;
}

int main() {
    AFuncToTest<int, int8_t>();
}

ВЫВОД: «не получается!»

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

Это не имеет ничего общего с C++20... подумайте, что будет enable_if_t<> оценивать.

Ahmed AEK 28.08.2024 19:18

Тип std::enable_if_t<true || false> не является int8_t.

molbdnilo 28.08.2024 19:29

Потому что у вас есть два разных шаблона функций. AFuncToTest<int, int8_t>() не соответствует второму перегруженному шаблону.

3CxEZiVlQ 28.08.2024 19:29

Во втором примере у вас есть параметр шаблона, не относящийся к типу. Это означает, что он ожидает значение типа int8_t, а не сам тип (если вы хотите сопоставить вторую перегрузку)

AndyG 28.08.2024 19:37

Вы пытаетесь выполнить частичную специализацию шаблона, но в конечном итоге вы используете параметр шаблона, не относящийся к типу.... поскольку речь идет о С++ 20, изучите концепции, в противном случае вам нужно будет найти частичную специализацию шаблона.

Ahmed AEK 28.08.2024 19:40

В C++20 вы можете использовать перегрузку с ограничением Демо

Jarod42 28.08.2024 23:33
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
66
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы используете std::enable_if_t неправильно. Этой ошибке посвящен раздел «Примечания» на сайте cppreference.com.

У вас есть два разных шаблона функций. AFuncToTest<int, int8_t>() не соответствует второму перегруженному template <typename T, void> void AFuncToTest().

Что касается второго фрагмента кода в вопросе, вы можете захотеть

template <typename T, typename E,
          std::enable_if_t<
              std::is_same_v<E, int8_t> || std::is_same_v<E, int16_t>, int> = 0>
void AFuncToTest() {
  std::cout << "int value!" << std::endl;
}

Теперь вы получаете error: call to 'AFuncToTest' is ambiguous, потому что два шаблона соответствуют типам шаблонов. Первый шаблон должен быть

template <
    typename T, typename E,
    std::enable_if_t<!std::is_same_v<E, int8_t> && !std::is_same_v<E, int16_t>,
                     int> = 0>
void AFuncToTest() {
  std::cout << "it fails!" << std::endl;
}

Результатом является значение int!

Этот

template <typename T, int8_t>
void AFuncToTest()

спички

AFuncToTest<int, (int8_t)1>();

и не

AFuncToTest<int, int8_t>();

То есть вы обещали значение типа int8_t, а не типа.

Чтобы специализироваться, вы ищете

template <typename T>
void AFuncToTest<T, int8_t>()

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

Подробный пример см. в этом ответе Альфа.

Ответ принят как подходящий

Похоже, вы пытаетесь активировать функцию AFuncToTest, когда ее аргумент шаблона T равен int8_t или int16_t. Я говорю это, потому что условие, которое вы предоставляете, проверяет только параметр T. Он не проверяет параметр E.

// from the OP:
std::enable_if_t<std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>>

Если это правда, то параметр шаблона E вам не нужен. Одного параметра T достаточно. Параметр E, видимо, предназначался для фиксации результата «enable_if_t», но в этом нет необходимости.

В следующем примере используется перегрузка функции, а не специализация шаблона функции. Содержащиеся в нем параметры enable_if_t позволяют вам «включать» или «выключать» конкурирующие перегрузки.

Когда условие в параметре enable_if_t принимает значение false, enable_if_t становится неверным, и использующая его перегрузка не будет скомпилирована. Однако из-за SFINAE сбой игнорируется (и не вызывает ошибку компиляции), а перегрузка отбрасывается. См. CppReference.

// main.cpp
#include <cstdint>
#include <iostream>
#include <type_traits>

// This is a "variable template."
template< typename T >
inline constexpr bool is_int8_or_int16 
    = std::is_same_v<T, std::int8_t> || std::is_same_v<T, std::int16_t>;

// Note the "logical not" operator (i.e., the exclation point).
template< typename T, std::enable_if_t<!is_int8_or_int16<T>, bool> = true >
void AFuncToTest()
{
    std::cout << "it fails!" << std::endl;
}

// There is no "logical not" here.
template< typename T, std::enable_if_t<is_int8_or_int16<T>, bool> = true >
void AFuncToTest()
{
    std::cout << "int value!" << std::endl;
}

int main()
{
    AFuncToTest<int>();          // outputs "it fails!"
    AFuncToTest<std::int8_t>();  // outputs "int value!"
}
// end file: main.cpp

Выход:

it fails!
int value!

Ограничения на помощь

В комментарии ниже @Jarod42 указывает, что ОП использует C++20, и предоставляет следующее решение, которое действует в C++20 (и более поздних версиях). В этом решении используется предложение требует , чтобы разместить ограничение на параметре шаблона T.

// main.cpp 
// Solution by @Jarod42
#include <iostream>
#include <type_traits>

template <typename T> void AFuncToTest()
{
    std::cout << "it fails!" << std::endl;
}

template <typename T>
    requires (std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>)
void AFuncToTest()
{
    std::cout << "int value!" << std::endl;
}

int main()
{
    AFuncToTest<int8_t>();
    AFuncToTest<int32_t>();
}
// end file: main.cpp

Как и выше, это работает через перегрузку функций.

  • Если ограничение не удовлетворяется, определение функции, в котором оно появляется, становится неверным и выпадает из набора перегрузок.
  • В противном случае, когда ограничение будет выполнено, набор перегрузок будет состоять из двух функций с именем AFuncToTest. Поскольку остальные критерии выбора перегрузки равны (в случае функции AFuncToTest), компилятор выбирает перегрузку, которая «более» ограничена.

Понятие «более» ограничений имеет точное определение, которое включает в себя идею о том, что одно ограничение включает в себя другое. Однако в большинстве случаев все, что вам нужно, — это интуитивное понимание того, является ли данная перегрузка «более» ограниченной, чем другая.

Поскольку OP использует C++20, std::enable_if не требуется, просто используйте ограничение Demo.

Jarod42 28.08.2024 23:36

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

Специализация шаблона C++ STD внутри другого пространства имен
Почему определение оператора = (а не объявление) должно быть написано, когда подходящий шаблон легко доступен
Использование SFINAE в конструкторе, чтобы проверить, существует ли конструктор типа члена
Использование if-constexpr и концепций для обнаружения экземпляра определенного типа расширенной политики
Почему квалификатор const игнорируется при применении к выведенной ссылке Lvalue в C++?
Создание декартова произведения на основе аргумента шаблона целочисленного диапазона
Почему выведение std::call_once не удалось и возникла ошибка «не удалось вывести параметр шаблона ‘_Callable’»
Невозможно получить доступ к специализации класса шаблона через универсальную ссылку
Вывести класс шаблона с уменьшенным количеством параметров шаблона
Как добавить собственный класс CSS в навигационное меню WooCommerce MyAccount?

Похожие вопросы

Почему C++ выбирает перегрузку базового класса при использовании указателя на функцию-член производного класса?
Почему возникает состояние гонки, когда аппаратное обеспечение обеспечивает согласованность
Производный виджет Gtk::DrawingArea загружается из файла компоновщика Glade неправильно
Ошибка нарушения прав доступа при многопоточном сканировании диска с помощью C++
Является ли замена всех const std::string & на std::string_view хорошим выбором?
C++ Неопределенное поведение при использовании переинтерпретации приведения
Как получить понятное имя, принадлежащее дескриптору HMONITOR в Windows?
Цикл while в C++ завершается сбоем, если целое число содержит более 10 цифр
Какова точная цитата из стандарта C++, в которой говорится, что ошибка вывода типа при выведении аргумента шаблона не является ошибкой (SFINAE)?
Метод удаления двоичного дерева поиска удаляет все узлы, а не только выбранный C++