Какие функции оболочки стандартной библиотеки C ++ вы используете? - PullRequest
81 голосов
/ 31 марта 2010

Этот вопрос , заданный сегодня утром, заставил меня задуматься о том, какие функции, по вашему мнению, отсутствуют в стандартной библиотеке C ++, и как вы справились с заполнением пробелов функциями-обертками. Например, моя собственная служебная библиотека имеет эту функцию для векторного добавления:

template <class T>
std::vector<T> & operator += ( std::vector<T> & v1,
                               const std::vector <T> & v2 ) {
    v1.insert( v1.end(), v2.begin(), v2.end() );
    return v1;
}

и этот для очистки (более или менее) любого типа - особенно полезен для таких вещей, как std :: stack:

template <class C>
void Clear( C & c ) {
    c = C();
}

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

Ответы [ 26 ]

1 голос
/ 21 апреля 2010

ИМО должно быть больше функциональности для pair:

#ifndef pair_iterator_h_
#define pair_iterator_h_

#include <boost/iterator/transform_iterator.hpp>    
#include <functional>
#include <utility>    

// pair<T1, T2> -> T1
template <typename PairType>
struct PairGetFirst : public std::unary_function<PairType, typename PairType::first_type>
{
    typename typename PairType::first_type& operator()(PairType& arg) const
    {       return arg.first;   }
    const typename PairType::first_type& operator()(const PairType& arg) const
    {       return arg.first;   }
};



// pair<T1, T2> -> T2
template <typename PairType>
struct PairGetSecond : public std::unary_function<PairType, typename PairType::second_type>
{
    typename PairType::second_type& operator()(PairType& arg) const
    {       return arg.second;  }
    const typename PairType::second_type& operator()(const PairType& arg) const
    {       return arg.second;  }
};



// iterator over pair<T1, T2> -> iterator over T1
template <typename Iter>
boost::transform_iterator<PairGetFirst<typename std::iterator_traits<Iter>::value_type>, Iter> 
make_first_iterator(Iter i)
{
    return boost::make_transform_iterator(i, 
        PairGetFirst<typename std::iterator_traits<Iter>::value_type>());
}



// iterator over pair<T1, T2> -> iterator over T2
template <typename Iter>
boost::transform_iterator<PairGetSecond<typename std::iterator_traits<Iter>::value_type>, Iter> 
make_second_iterator(Iter i)
{
    return boost::make_transform_iterator(i, 
        PairGetSecond<typename std::iterator_traits<Iter>::value_type>());
}



// T1 -> pair<T1, T2>
template <typename FirstType, typename SecondType>
class InsertIntoPair1st : public std::unary_function<FirstType, std::pair<FirstType, SecondType> >
{
public:
    InsertIntoPair1st(const SecondType& second_element) : second_(second_element) {}
    result_type operator()(const FirstType& first_element)
    {
        return result_type(first_element, second_);
    }
private:
    SecondType second_;
};



// T2 -> pair<T1, T2>
template <typename FirstType, typename SecondType>
class InsertIntoPair2nd : public std::unary_function<SecondType, std::pair<FirstType, SecondType> >
{
public:
    InsertIntoPair2nd(const FirstType& first_element) : first_(first_element) {}
    result_type operator()(const SecondType& second_element)
    {
        return result_type(first_, second_element);
    }
private:
    FirstType first_;
};

#endif // pair_iterator_h_
1 голос
/ 31 марта 2010

Вставьте новый элемент и верните его, что полезно для простой семантики перемещения, такой как push_back(c).swap(value) и связанных с ней случаев.

template<class C>
typename C::value_type& push_front(C& container) {
  container.push_front(typename C::value_type());
  return container.front();
}

template<class C>
typename C::value_type& push_back(C& container) {
  container.push_back(typename C::value_type());
  return container.back();
}

template<class C>
typename C::value_type& push_top(C& container) {
  container.push(typename C::value_type());
  return container.top();
}

Взять и вернуть предмет:

template<class C>
typename C::value_type pop_front(C& container) {
  typename C::value_type copy (container.front());
  container.pop_front();
  return copy;
}

template<class C>
typename C::value_type pop_back(C& container) {
  typename C::value_type copy (container.back());
  container.pop_back();
  return copy;
}

template<class C>
typename C::value_type pop_top(C& container) {
  typename C::value_type copy (container.top());
  container.pop();
  return copy;
}
0 голосов
/ 15 апреля 2016

Неупорядоченное стирание для std::vector. Самый эффективный способ стереть элемент из vector, но это не сохраняет порядок элементов. Я не видел смысла распространять его на другие контейнеры, так как у большинства нет одинакового штрафа за удаление предметов из середины. Он похож на некоторые другие шаблоны, которые уже были опубликованы, но для перемещения элементов вместо копирования используется std::swap.

template<typename T>
void unordered_erase(std::vector<T>& vec, const typename std::vector<T>::iterator& it)
{
    if (it != vec.end()) // if vec is empty, begin() == end()
    {
        std::swap(vec.back(), *it);
        vec.pop_back();
    }
}

Signum возвращает знак типа. Возвращает -1 для отрицательного значения, 0 для нулевого значения и 1 для положительного значения.

template <typename T>
int signum(T val)
{
    return (val > T(0)) - (val < T(0));
}

Зажим довольно понятен, он фиксирует значение так, чтобы оно лежало в заданном диапазоне. Меня поражает, что Стандартная библиотека включает в себя min и max, но не clamp

template<typename T>
T clamp(const T& value, const T& lower, const T& upper)
{
    return value < lower ? lower : (value > upper ? upper : value);
}
0 голосов
/ 21 апреля 2010

Подобно тому, что люди писали ранее, У меня есть удобные перегрузки алгоритмов для упрощения передачи аргументов итератора. Я называю алгоритмы так:

for_each(iseq(vec), do_it());

Я перегрузил все алгоритмы так, что они принимают один параметр типа input_sequence_range<> вместо двух входных итераторов (ввод, как во всем, что не является просто выводом).

template<typename In>
struct input_sequence_range
: public std::pair<In,In>
{
    input_sequence_range(In first, In last)
        : std::pair<In,In>(first, last)
    { }
};

А вот так iseq() работает:

template<typename C>
input_sequence_range<typename C::const_iterator> iseq(const C& c)
{
    return input_sequence_range<typename C::const_iterator>(c.begin(),
                                                            c.end());
}

Точно так же у меня есть специализации для

  • const_iterators
  • указатели (примитивные массивы)
  • потоковые итераторы
  • любой диапазон [начало, конец) только для единообразного использования: используйте iseq () для всего
0 голосов
/ 02 апреля 2010

Не уверен, что они соответствуют стандартным упаковщикам, но мои обычно используемые вспомогательные функции:

void split(string s, vector<string> parts, string delims);
string join(vector<string>& parts, string delim);
int find(T& array, const V& value);
void assert(bool condition, string message);
V clamp(V value, V minvalue, V maxvalue);
string replace(string s, string from, string to);
const char* stristr(const char* a,const char*b);
string trim(string str);
T::value_type& dyn(T& array,int index);

T и V - это аргументы шаблона. Последняя функция работает так же, как [] -оператор, но с автоматическим изменением размера для соответствия необходимому индексу.

0 голосов
/ 01 апреля 2010

Один из моих любимых - Transposer, который находит транспозицию кортежа контейнеров одинакового размера. То есть, если у вас есть tuple<vector<int>,vector<float>>, он конвертирует его в vector<tuple<int, float>>. Пригодится в программировании XML. Вот как я это сделал.

#include <iostream>
#include <iterator>
#include <vector>
#include <list>
#include <algorithm>
#include <stdexcept>

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <boost/type_traits.hpp>

using namespace boost;

template <class TupleOfVectors>
struct GetTransposeTuple;

template <>
struct GetTransposeTuple<tuples::null_type>
{
  typedef tuples::null_type type;
};

template <class TupleOfVectors>
struct GetTransposeTuple
{
  typedef typename TupleOfVectors::head_type Head;
  typedef typename TupleOfVectors::tail_type Tail;
  typedef typename
    tuples::cons<typename remove_reference<Head>::type::value_type,
                 typename GetTransposeTuple<Tail>::type> type;
};

template <class TupleOfVectors,
          class ValueTypeTuple = 
                typename GetTransposeTuple<TupleOfVectors>::type,
          unsigned int TUPLE_INDEX = 0>
struct Transposer
  : Transposer <typename TupleOfVectors::tail_type,
                ValueTypeTuple,
                TUPLE_INDEX + 1>
{
  typedef typename remove_reference<typename TupleOfVectors::head_type>::type
    HeadContainer;
  typedef typename TupleOfVectors::tail_type Tail;
  typedef Transposer<Tail, ValueTypeTuple, TUPLE_INDEX + 1> super;
  typedef std::vector<ValueTypeTuple> Transpose;

  Transposer(TupleOfVectors const & tuple)
    : super(tuple.get_tail()),
      head_container_(tuple.get_head()),
      head_iter_(head_container_.begin())
  {}

  Transpose get_transpose ()
  {
    Transpose tran;
    tran.reserve(head_container_.size());
    for(typename HeadContainer::const_iterator iter = head_container_.begin();
        iter != head_container_.end();
        ++iter)
    {
      ValueTypeTuple vtuple;
      this->populate_tuple(vtuple);
      tran.push_back(vtuple);
    }
    return tran;
  }

private:

  HeadContainer const & head_container_;
  typename HeadContainer::const_iterator head_iter_;

protected:

  void populate_tuple(ValueTypeTuple & vtuple)
  {
    if(head_iter_ == head_container_.end())
      throw std::runtime_error("Container bound exceeded.");
    else
    {
      vtuple.get<TUPLE_INDEX>() = *head_iter_++;
      super::populate_tuple (vtuple);
    }
  }
};

template <class ValueTypeTuple,
          unsigned int INDEX>
struct Transposer <tuples::null_type, ValueTypeTuple, INDEX>
{
  void populate_tuple(ValueTypeTuple &) {}
  Transposer (tuples::null_type const &) {}
};

template <class TupleOfVectors>
typename Transposer<TupleOfVectors>::Transpose
transpose (TupleOfVectors const & tupleofv)
{
  return Transposer<TupleOfVectors>(tupleofv).get_transpose();
}

int main (void)
{
  typedef std::vector<int> Vint;
  typedef std::list<float> Lfloat;
  typedef std::vector<long> Vlong;

  Vint vint;
  Lfloat lfloat;
  Vlong vlong;

  std::generate_n(std::back_inserter(vint), 10, rand);
  std::generate_n(std::back_inserter(lfloat), 10, rand);
  std::generate_n(std::back_inserter(vlong), 10, rand);

  typedef tuples::tuple<Vint, Lfloat, Vlong> TupleOfV;
  typedef GetTransposeTuple<TupleOfV>::type TransposeTuple;

  Transposer<TupleOfV>::Transpose tran = 
    transpose(make_tuple(vint, lfloat, vlong));
  // Or alternatively to avoid copying
  // transpose(make_tuple(ref(vint), ref(lfloat), ref(vlong)));
  std::copy(tran.begin(), tran.end(),
            std::ostream_iterator<TransposeTuple>(std::cout, "\n"));

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