Специализация шаблона функции в C , отсутствие экземпляра перегруженной функции

#c #templates #overload-resolution #function-templates-overloading

Вопрос:

Я изучаю специализацию шаблонов функций в C , и мне поручено написать функцию шаблона plus , которая возвращает сумму двух аргументов, которые могут быть разных типов. Одна версия, которая принимает значение, а другая-указатель. В качестве дополнительной задачи меня просят перегрузить эту функцию, чтобы она объединяла две строки.

 template lt;typename T1, typename T2gt; decltype(auto) plus(const T1amp; a, const T2amp; b) {  return a   b; }  template lt;typename T1, typename T2gt; decltype(auto) plus(const T1* a, const T2* b) {  return *a   *b; }  // concatenate two strings template lt;gt; std::string_view pluslt;std::string_view, std::string_viewgt; (std::string_view a, std::string_view b) {  return std::string { a }   std::string{ b }; }  

Проблема в том, что я получаю ошибку при перегрузке специализации функции для объединения двух строк. Причина, по которой я решил сделать выбор std::string_view std::string , заключается в том, что при вызове функции со строковыми литералами ( const char* ) она не будет разрешена до второго определения, которое принимает const * значение, которое, как я предполагаю, будет решено std::string .

Так что я действительно не могу понять, что происходит. Просто дикое предположение, но, может быть, это как-то связано с тем, что у меня вызваны две разные функции шаблона plus , и он не может понять, на какой из них я пытаюсь специализироваться / перегрузить?

Обновить:

Проблема, похоже, связана с разрешением шаблона. Определение, которое принимает const T* , всегда предпочтительнее для любых строковых литералов. Просто пытаюсь найти решение.

Комментарии:

1. Шаблон-это отвлекающий маневр. Для строковых представлений не определен оператор . У вас возникла бы эта проблема в обычной функции, не связанной с шаблоном.

2. @RaymondChen исправлено, у меня был std::string конструктор, в мой код просто вставили неправильное определение.

3. @RaymondChen Я также пытался специализироваться const char* специально для строковых литералов, но все равно проблема не в экземпляре перегруженной функции.

4. Я сузил проблему до разрешения функциональной нагрузки. Независимо от того, как я специализирую шаблон, он все равно предпочитает второе определение, которое использует указатели.

Ответ №1:

Это было бы моим предложением:

 template lt;typename T1, typename T2, typename T3gt; T3 plus(const T1amp; a, const T2amp; b) {  return a   b; }  template lt;typename T1, typename T2, typename T3gt; T3 plus(const T1* a, const T2* b) {  return *a   *b; }  template lt;typename T1, typename T2, typename T3gt; T3 plus(T1 a, T2 b) {  return a   b; }  // concatenate two strings template lt;gt; std::string pluslt;std::string_view, std::string_viewgt; (std::string_view a, std::string_view b) {  return std::string(a).append(b); }  

Поскольку строковые представления должны ссылаться на содержимое другой строки, вам необходимо вернуть строку, так как вновь созданный string_view будет указывать на временный объект.

Кроме того, невозможно объединить 2 представления string_view вместе, поскольку для объединения двух строк вместе потребуется, чтобы представления string_view могли содержать ссылки на другие представления строк (поскольку они сами не содержат содержимого строки).

Кроме того, требуется третье имя типа, так как эта реализация вернет другой тип (std::string), так как вы не хотите возвращать string_view временного

Ответ №2:

Если у вас есть доступ к C 20, то это можно довольно легко сделать с помощью концепций.

Все , что можно преобразовать в string_view , например, string и const char* , будет использовано для этой функции:

 templatelt;typename Tgt; concept StringView = std::convertible_tolt;T, std::string_viewgt;;  auto plus(StringView auto a, StringView auto b)  {  return std::string(a).append(b); }  

Аналогичным образом, вы можете легко определить другие понятия и просто указать StringView :

 templatelt;typename Tgt; concept Reference = std::is_reference_vlt;Tgt; amp;amp; !StringViewlt;Tgt;;  templatelt;typename Tgt; concept Pointer = std::is_pointer_vlt;Tgt; amp;amp; !StringViewlt;Tgt;;  auto plus(const Reference auto a, const Reference auto b) {  ⋮  ⋮