Как выразить ограничение в терминах другой концепции

#c #c 20 #c -concepts

Вопрос:

Вероятно, проще всего конкретно описать то, что я пытаюсь решить, чтобы это было легче понять.

У меня есть SmartPointer концепция, так что у меня могут быть функции, которые могут принимать или std::unique_ptr std::shared_ptr :

 template lt;typename Tgt; concept SmartPointer = requires(const Tamp; t) {  requires std::same_aslt;decltype(t.get()), typename T::pointergt;; };  

Я хочу создать функцию, которая может принимать пару итераторов, где тип значения итератора должен иметь тип SmartPointer , и мне не нужно явно определять какие-либо типы.

Я могу создать функцию, которая имеет параметр шаблона с ограничением SmartPointer, и проверить это:

 template lt;SmartPointer T, std::forward_iterator TIterator, std::sentinel_forlt;TIteratorgt; TIteratorSentinelgt;  requires std::same_aslt;std::iter_value_tlt;TIteratorgt;, Tgt; void doWithSmartPointers(TIterator begin, TIteratorSentinel end) {  for (auto it = begin; it != end;   it) {  // Some logic with it-gt;get() etc.  } }  

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

 std::vectorlt;std::unique_ptrlt;intgt;gt; v{}; v.push_back(std::make_uniquelt;intgt;(1)); v.push_back(std::make_uniquelt;intgt;(2)); v.push_back(std::make_uniquelt;intgt;(3)); doWithSmartPointer(v.begin(), v.end()); // Error, couldn't infer template argument T doWithSmartPointlt;std::unique_ptrlt;intgt;gt;(v.begin(), v.end()); // OK  

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

По сути, я хочу чего-то подобного:

 template lt;std::forward_iterator TIterator, std::sentinel_forlt;TIteratorgt; TIteratorSentinelgt;  requires std::same_aslt;std::iter_value_tlt;TIteratorgt;, SmartPointergt; // Not valid syntax! void doWithSmartPointers(TIterator begin, TIteratorSentinel end) {  for (auto it = begin; it != end;   it) {  // Some logic with it-gt;get() etc.  } }  

Правильно ли я поступаю в этом вопросе? Возможно ли это вообще? Заранее благодарю вас!

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

1. В стороне: обычно вам не нужно использовать get интеллектуальный указатель, -gt; он вычисляется рекурсивно

Ответ №1:

Вам не нужен T параметр шаблона:

 template lt; std::forward_iterator TIterator  , std::sentinel_forlt;TIteratorgt; TIteratorSentinel gt;  requires SmartPointerlt; std::iter_value_tlt;TIteratorgt; gt;  // ^^^^^^^^^^^^ void whatever(TIterator begin, TIteratorSentinel end) {  // ... }  

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

1. Ах, блестяще, спасибо! Я думал, что это должно быть возможно 🙂

Ответ №2:

Если у вас много таких шаблонных функций whatever , возможно, стоит определить концепцию «итератора, указывающего на интеллектуальный указатель».

 template lt;typename Tgt; concept SmartPointerIterator = requires std::forward_iteratorlt;Tgt; amp;amp; SmartPointerlt;std::iter_value_tlt;Tgt;gt;;  template lt; SmartPointerIterator TIterator  , std::sentinel_forlt;TIteratorgt; TIteratorSentinel gt; void whatever(TIterator begin, TIteratorSentinel end) {  // ... }