Выполнять различные функции в зависимости от нарушения параметров шаблона

Это определенно тривиальный вопрос, но я не мог понять, как это сделать.

У меня есть функция шаблона, скажем 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>{}(); }