Как добавить специализацию шаблона для универсального метода в универсальном классе, когда два типа равны?

Я пытаюсь добавить специализацию, в которой общий тип метода и класса согласуются, но я не смог точно понять, как указать экземпляр шаблона (если это вообще возможно).

Мое лучшее предположение было бы примерно следующим (хотя оно явно не компилируется):

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;
}

Должна ли это быть специализация или подойдет обычная перегрузка?

chris 11.01.2023 03:09

К сожалению, класс-шаблон должен быть специализирован до того, как можно будет специализировать любой из его методов-шаблонов.

Sam Varshavchik 11.01.2023 03:14

Крис, если перегрузка работает, это было бы здорово, но я не думаю, что можно было бы обойтись без перечисления каждого типа, верно?

Dyllon Gagnier 11.01.2023 18:12
Ускорьте разработку веб-приложений Laravel с помощью этих бесплатных стартовых наборов
Ускорьте разработку веб-приложений Laravel с помощью этих бесплатных стартовых наборов
Laravel - это мощный PHP-фреймворк, используемый для создания масштабируемых и надежных веб-приложений. Одним из преимуществ Laravel является его...
Что такое двойные вопросительные знаки (??) в JavaScript?
Что такое двойные вопросительные знаки (??) в JavaScript?
Как безопасно обрабатывать неопределенные и нулевые значения в коде с помощью Nullish Coalescing
Создание ресурсов API Laravel: Советы по производительности и масштабируемости
Создание ресурсов API Laravel: Советы по производительности и масштабируемости
Создание API-ресурса Laravel может быть непростой задачей. Она требует глубокого понимания возможностей Laravel и лучших практик, чтобы обеспечить...
Как сделать компонент справочного центра с помощью TailwindCSS
Как сделать компонент справочного центра с помощью TailwindCSS
Справочный центр - это веб-сайт, где клиенты могут найти ответы на свои вопросы и решения своих проблем. Созданный для решения многих распространенных...
Асинхронная передача данных с помощью sendBeacon в JavaScript
Асинхронная передача данных с помощью sendBeacon в JavaScript
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных...
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Отказ от ответственности: Эта статья предназначена только для демонстрации и не должна использоваться в качестве инвестиционного совета.
0
3
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Как обсуждалось в комментариях, это невозможно сделать со специализацией шаблона. Однако нечто подобное можно сделать, используя 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>)
{
}

Другие вопросы по теме