Вы можете использовать частичную специализацию шаблона в сочетании с SFINAE для достижения этой цели:
#include <type_traits>
template <class T, typename = void>
class State
{
T state;
public:
void set(T newState)
{
state = newState;
}
T get()
{
return state;
}
};
template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{
T state;
public:
void set(int newState)
{
state = newState;
}
int get()
{
return state;
}
int multiplyState(int n)
{
return state*n;
}
};
живой пример здесь
Хитрость здесь заключается в использованииВторой параметр шаблона (который может быть безымянным и имеет аргумент по умолчанию).Когда вы используете специализацию вашего шаблона класса, например, State<some_type>
, компилятор должен выяснить, какой из шаблонов следует использовать.Чтобы сделать это, он должен каким-то образом сравнить заданные аргументы шаблона с каждым шаблоном и решить, какой из них лучше всего подходит.
Способ, которым на самом деле выполняется это сопоставление, заключается в попытке вывести аргументы каждой частичной специализации изданный шаблон аргументов.Например, в случае State<int>
аргументы шаблона будут int
и void
(последний существует из-за аргумента по умолчанию для второго параметра основного шаблона).Затем мы пытаемся вывести аргументы для нашей единственной частичной специализации
template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>;
из аргументов шаблона int, void
.Наша частичная специализация имеет единственный параметр T
, который может быть напрямую выведен из первого аргумента шаблона как int
.И с этим мы уже закончили, так как мы вывели все параметры (здесь только один).Теперь подставим выведенные параметры в частичную специализацию: State<T, std::enable_if_t<std::is_arithmetic_v<T>>>
.В итоге мы получим State<int, void>
, который соответствует списку начальных аргументов int, void
.Следовательно, применяется частичная специализация шаблонов.
Теперь, если вместо этого мы написали State<some_type>
, где some_type
не является арифметическим типом, то процесс будет таким же, вплоть до того момента, когда мыуспешно вывели параметр для частичной специализации как some_type
.Мы снова подставляем параметр обратно в частичную специализацию State<T, std::enable_if_t<std::is_arithmetic_v<T>>>
.Тем не менее, std::is_arithmetic_v<some_type>
теперь будет false
, что приведет к тому, что std::enable_if_t<…>
не будет определено, и замена не удастся.Поскольку ошибка замены не является ошибкой в этом контексте, это просто означает, что частичная специализация здесь не вариант, и вместо нее будет использоваться первичный шаблон.
Если было несколько совпадающих частичныхспециализации, они должны были бы быть ранжированы, чтобы выбрать лучший матч. Фактический процесс довольно сложен, но обычно сводится к выбору наиболее конкретной специализации.