#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) { ⋮ ⋮