Выполнять различные функции в зависимости от нарушения параметров шаблона
Это определенно тривиальный вопрос, но я не мог понять, как это сделать.
У меня есть функция шаблона, скажем template <unsigned int N> void my_function()
. Теперь у меня есть две разные реализации для my_function
, первая должна использоваться, если N
больше, чем, скажем, 100, другая, если N
меньше этого.
Я попытался использовать SFINAE следующим образом:
template <unsigned int N, typename = enable_if <N >= 100> :: type> my_function()
{
// First implementation
}
template <unsigned int N, typename = enable_if <N < 100> :: type> my_function()
{
// Second implementation
}
Но это объявляет одну и ту же функцию два раза. Затем я попытался сделать что-то вроде
template <unsigned int N, bool = (N >= 100)> my_function();
И затем реализуем две функции с двумя разными значениями логического. Нет успеха, поскольку это частичная специализация.
Затем я попытался обернуть N
в качестве параметра struct и bool в вызове функции, но он специализируется на функции-члене, прежде чем специализировать класс, что не может быть выполнено.
Есть ли разумный способ сделать это?
Ответы
Ответ 1
Попробуйте это вместо:
#include <type_traits>
#include <iostream>
template <unsigned int N, typename std::enable_if <N >= 100> :: type* = nullptr>
void my_function()
{
std::cout << "N >= 100" << std::endl;
}
template <unsigned int N, typename std::enable_if <N < 100> :: type* = nullptr>
void my_function()
{
std::cout << "N < 100" << std::endl;
}
int main()
{
my_function<42>();
my_function<100>();
}
Параметры шаблона по умолчанию не участвуют в перегрузке (и, следовательно, SFINAE не применяется). С другой стороны, в вышеприведенном фрагменте параметр зависимого шаблона не-типа находится в левой части задания, поэтому SFINAE выполняет вход.
Ответ 2
Если вам почему-то не нравится enable_if, вы всегда можете пойти на отправку тегов:
#include <type_traits>
class low {};
class high {};
template <int N, class T>
void func(T, low)
{
// version for high N
}
template <int N, class T>
void func(T, high)
{
// version for low N
}
template <int N, class T>
void func(T val)
{
func<N>(val, std::conditional_t<(N>=100), high, low>{});
}
int main()
{
func<3>(3.14159); // low version
func<256>("Yo"); // high version
}
В этом случае мы могли бы ограничить теги простыми вещами, такими как true_type и false_type, но в целом это может быть альтернативный подход.
Ответ 3
Вы можете использовать SFINAE по типу возврата:
template <unsigned int N>
enable_if_t<(N >= 100)> my_function()
{
// First implementation
}
template <unsigned int N>
enable_if_t<(N < 100)> my_function()
{
// Second implementation
}
в настоящее время у вас есть только template <unsigned int N, typename T>
с другим типом по умолчанию для T
.
Для частичной специализации вы можете переслать структуру:
template <unsigned int N, bool = (N >= 100)>
struct my_function_impl;
template <unsigned int N>
struct my_function_impl<N, true>
{
void operator () const { /* First implementation */}
};
template <unsigned int N>
struct my_function_impl<N, false>
{
void operator () const { /* Second implementation */}
};
template <unsigned int N>
void my_function() { my_function_impl<N>{}(); }