Как в этом случае работает специализация шаблонов в 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>();
}
ВЫВОД: «не получается!»
Поэтому я думаю, что мне не хватает какой-то концепции шаблонов, которая не соответствует правильному результату.
Тип std::enable_if_t<true || false>
не является int8_t
.
Потому что у вас есть два разных шаблона функций. AFuncToTest<int, int8_t>()
не соответствует второму перегруженному шаблону.
Во втором примере у вас есть параметр шаблона, не относящийся к типу. Это означает, что он ожидает значение типа int8_t
, а не сам тип (если вы хотите сопоставить вторую перегрузку)
Вы пытаетесь выполнить частичную специализацию шаблона, но в конечном итоге вы используете параметр шаблона, не относящийся к типу.... поскольку речь идет о С++ 20, изучите концепции, в противном случае вам нужно будет найти частичную специализацию шаблона.
В C++20 вы можете использовать перегрузку с ограничением Демо
Вы используете 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.
Это не имеет ничего общего с C++20... подумайте, что будет
enable_if_t<>
оценивать.