Шаблон функции для запуска в коллекциях, который имеет функцию «преобразования» по умолчанию, которая ничего не делает - PullRequest
0 голосов
/ 26 марта 2019

Я написал функцию Join для коллекций, которая позволяет создавать объединенную строку для любой строки, подобной классу, которая поддерживает оператор <<.Я хочу сделать это так, чтобы, если ваша коллекция не была набором строк, вы можете передать функцию преобразования, которая возвращает константную ссылку на нужное вам поле «stringified».

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

Я бы хотел, чтобы FunctStringer по умолчанию использовала функцию идентификации, которая в этом случае принимает Collection::value_typeстандартных коллекций, но это также будет работать с нативными массивами.

Идеи?Вот код шаблона:

    // Collection::value_type must be able to be streamed into "output"
    template<typename Collection, typename Delimiter, typename Output>
    void Join(const Collection &collection, const Delimiter &delimiter, Output &output)
    {
        if (!std::empty(collection))
        {
            auto iter = std::begin(collection);
            // output the first item
            output << *iter;
            iter++;

            for ( ;iter != std::end(collection); iter++)
            {
                output << delimiter;
                output << *iter;
            }
        }
    }

    // Collection::value_type must be able to be streamed into "output"
    template<typename Collection, typename Delimiter, typename Output, typename FunctStringer>
    void Join(const Collection &collection, const Delimiter &delimiter, Output &output, FunctStringer s)
    {
        if (!std::empty(collection))
        {
            auto iter = std::begin(collection);
            // output the first item
            output << s(*iter);
            iter++;

            for (; iter != std::end(collection); iter++)
            {
                output << delimiter;
                output << s(*iter);
            }
        }
    }

Ответы [ 2 ]

1 голос
/ 26 марта 2019

Если я понял вопрос, почему не что-то вроде

struct NoOpStringer {
    template<class ARG> const ARG& operator()(const ARG& arg) {
         return arg;
    }
}

, а затем

template<typename Collection, typename Delimiter, typename Output, typename FunctStringer = NoOpStringer>
void Join(const Collection &collection, const Delimiter &delimiter, Output &output, FunctStringer s = FunctStringer{})
0 голосов
/ 26 марта 2019

Другое решение, основанное на static const лямбда-функции для функции идентификации.

К сожалению, требуется C ++ 14 (использует универсальную лямбду), но, как вы можете видеть, я также изменил функцию наиспользуйте циклический цикл, чтобы больше не нуждаться в итераторах и работает также для массивов в стиле C.

#include <vector>
#include <iostream>

static const auto l = [](auto item){ return item; };

template <typename C, typename D, typename O, typename F = decltype(l)>
void Join (C const & c, D const & d, O & o, F f = l)
 {
   bool  first { true };

   for ( auto const & item : c )
    {
      if ( first )
         first = false;
      else
         o << d;

      o << f(item);
    }

 }

int main()
 {
   std::vector<int>  v1 { 2, 3, 5, 7, 11, 13, 17 };

   int  v2[] { 1, 2, 3, 4, 5 };

   Join(v1, ',', std::cout);

   std::cout << std::endl;

   Join(v2, ',', std::cout, [](auto i){ return i+10; });

   std::cout << std::endl;
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...