Я пытаюсь добавить специализацию, в которой общий тип метода и класса согласуются, но я не смог точно понять, как указать экземпляр шаблона (если это вообще возможно).
Мое лучшее предположение было бы примерно следующим (хотя оно явно не компилируется):
template<typename ClassT>
class Foo
{
public:
ClassT x;
template<typename MethodT>
void Bar(MethodT arg)
{
}
};
template<typename T>
template<>
void Foo<T>::Bar(T arg)
{
x = arg;
}
К сожалению, класс-шаблон должен быть специализирован до того, как можно будет специализировать любой из его методов-шаблонов.
Крис, если перегрузка работает, это было бы здорово, но я не думаю, что можно было бы обойтись без перечисления каждого типа, верно?
Как обсуждалось в комментариях, это невозможно сделать со специализацией шаблона. Однако нечто подобное можно сделать, используя std::enable_if_t и
template<typename ClassT>
class Foo
{
public:
ClassT x;
template<typename MethodT,
typename = std::enable_if_t<!std::is_same<ClassT, MethodT>::value>>
void Bar(MethodT arg)
{
}
void Bar(ClassT arg)
{
x = arg;
}
};
Std::enable_if_t будет возвращать допустимый тип только в том случае, если аргумент типа ввода имеет значение true. Таким образом, подстановка шаблона завершится ошибкой, если MethodT и ClassT имеют один и тот же тип, но перегрузка без шаблона не завершится ошибкой. Ошибка замены шаблона допустима в SFINAE.
Как это обычно бывает при рассмотрении специализации шаблона функции, перегрузка может справиться с этим:
template<typename MethodT>
void Bar(MethodT arg)
{
}
void Bar(ClassT arg)
{
x = arg;
}
Когда вы вызываете Bar, один из кандидатов будет специализацией шаблона функции, а другой — нет. Думайте о шаблоне класса как о штамповке реальных, конкретных функций-членов, где это возможно, при его создании. Довольно поздно в разрешении перегрузки существует правило, предпочитающее тот, который не является специализацией шаблона функции, если это связано с этим моментом.
В итоге вы получаете вторую перегрузку, которая вызывается, когда есть «точное совпадение» в типах (что допускает разницу в верхнем уровне const). Если точные совпадения слишком узкие, вы можете ограничить первую перегрузку, чтобы расширить вторую:
// Allow the other overload to win in cases like Foo<int>{}.Bar(0.0).
// std::enable_if works as well before C++20.
template<typename MethodT>
void Bar(MethodT arg) requires (not std::convertible_to<MethodT, ClassT>)
{
}
Должна ли это быть специализация или подойдет обычная перегрузка?