turbo sirve que para librerias las diseño dev descargar clasificacion clases c++

sirve - ¿Qué funciones de contenedor de la biblioteca estándar de C++ usas?



librerias de dev c++ (26)

Envolver sprintf

string example = function("<li value=''%d''>Buffer at: 0x%08X</li>", 42, &some_obj); // ''function'' is one of the functions below: Format or stringf

El objetivo es desacoplar el formato de la salida sin tener problemas con sprintf y su tipo. No es bonito, pero es muy útil, especialmente si tus directrices de codificación prohíben iostreams.

Aquí hay una versión que asigna según sea necesario, de Neil Butterworth. [Ver el historial de revisión de la versión de Mike, que eliminé como un subconjunto de los otros dos. Es similar a la de Neil, excepto que este último es a prueba de excepciones mediante el uso de vector en lugar de eliminar []: el ctor de cadena lanzará en la falla de asignación. Mike también usa la misma técnica que se muestra más adelante para determinar el tamaño por adelantado. -RP]

string Format( const char * fmt, ... ) { const int BUFSIZE = 1024; int size = BUFSIZE, rv = -1; vector <char> buf; do { buf.resize( size ); va_list valist; va_start( valist, fmt ); // if _vsnprintf() returns < 0, the buffer wasn''t big enough // so increase buffer size and try again // NOTE: MSFT''s _vsnprintf is different from C99''s vsnprintf, // which returns non-negative on truncation // http://msdn.microsoft.com/en-us/library/1kt27hek.aspx rv = _vsnprintf( &buf[0], size, fmt, valist ); va_end( valist ); size *= 2; } while( rv < 0 ); return string( &buf[0] ); }

Aquí hay una versión que determina el tamaño necesario por adelantado, de Roger Pate . Esto requiere std :: strings escribibles, que son proporcionados por implementaciones populares, pero son requeridos explícitamente por C ++ 0x. [Ver el historial de revisiones de la versión de Marcus, que eliminé porque es un poco diferente, pero básicamente es un subconjunto del siguiente. -RP]

Implementación

void vinsertf(std::string& s, std::string::iterator it, char const* fmt, int const chars_needed, va_list args ) { using namespace std; int err; // local error code if (chars_needed < 0) err = errno; else { string::size_type const off = it - s.begin(); // save iterator offset if (it == s.end()) { // append to the end s.resize(s.size() + chars_needed + 1); // resize, allow snprintf''s null it = s.begin() + off; // iterator was invalidated err = vsnprintf(&*it, chars_needed + 1, fmt, args); s.resize(s.size() - 1); // remove snprintf''s null } else { char saved = *it; // save char overwritten by snprintf''s null s.insert(it, chars_needed, ''/0''); // insert needed space it = s.begin() + off; // iterator was invalidated err = vsnprintf(&*it, chars_needed + 1, fmt, args); *(it + chars_needed) = saved; // restore saved char } if (err >= 0) { // success return; } err = errno; it = s.begin() + off; // above resize might have invalidated ''it'' // (invalidation is unlikely, but allowed) s.erase(it, it + chars_needed); } string what = stringf("vsnprintf: [%d] ", err); what += strerror(err); throw runtime_error(what); }

Interfaz pública

std::string stringf(char const* fmt, ...) { using namespace std; string s; va_list args; va_start(args, fmt); int chars_needed = vsnprintf(0, 0, fmt, args); va_end(args); va_start(args, fmt); try { vinsertf(s, s.end(), fmt, chars_needed, args); } catch (...) { va_end(args); throw; } va_end(args); return s; } // these have nearly identical implementations to stringf above: std::string& appendf(std::string& s, char const* fmt, ...); std::string& insertf(std::string& s, std::string::iterator it, char const* fmt, ...);

Esta pregunta , hecha esta mañana, me hizo preguntarme qué características cree que faltan en la Biblioteca Estándar de C ++, y cómo ha ido llenando las lagunas con las funciones de envoltura. Por ejemplo, mi propia biblioteca de utilidades tiene esta función para vector append:

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; }

y este para borrar (más o menos) cualquier tipo, particularmente útil para cosas como std :: stack:

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

Tengo algunos más, pero estoy interesado en cuáles usar? Limite las respuestas a las funciones del contenedor , es decir, no más de un par de líneas de código.


A menudo uso el vector como un conjunto de elementos sin ningún orden en particular (y, obviamente, cuando no necesito verificaciones rápidas es-este-elemento-en-el-conjunto). En estos casos, llamar a erase () es una pérdida de tiempo ya que reordenará los elementos y no me importa el orden. Ahí es cuando la función O (1) a continuación es útil: simplemente mueva el último elemento en la posición del que desea eliminar:

template<typename T> void erase_unordered(std::vector<T>& v, size_t index) { v[index] = v.back(); v.pop_back(); }


A veces siento que estoy en el begin() y el end() infierno. Me gustaría tener algunas funciones como:

template<typename T> void sort(T& x) { std::sort(x.begin(), x.end()); }

y otros similares para std::find , std::for_each , y básicamente todos los algoritmos STL.

Creo que sort(x) es mucho más rápido de leer que de sort(x.begin(), x.end()) .


Aquí está mi conjunto de utilidades extra, construido sobre un contenedor boost-stock''ish std-algo que podría necesitar para algunas funciones. (Eso es trivial de escribir, esta es la cosa interesante)

#pragma once /** @file @brief Defines various utility classes/functions for handling ranges/function objects in addition to bsRange (which is a ranged version of the /<algorithm/> header) Items here uses a STL/boost-style naming due to their ''templatised'' nature. If template variable is R, anything matching range_concept can be used. If template variable is C, it must be a container object (supporting C::erase()) */ #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/smart_ptr.hpp> namespace boost { struct use_default; template<class T> class iterator_range; #pragma warning(disable: 4348) // redeclaration of template default parameters (this clashes with fwd-decl in boost/transform_iterator.hpp) template < class UnaryFunction , class Iterator , class Reference = use_default , class Value = use_default > class transform_iterator; template < class Iterator , class Value = use_default , class Category = use_default , class Reference = use_default , class difference = use_default > class indirect_iterator; template<class T> struct range_iterator; template < class Incrementable , class CategoryOrTraversal = use_default , class difference = use_default > class counting_iterator; template <class Predicate, class Iterator> class filter_iterator; } namespace orz { /// determines if any value that compares equal exists in container template<class R, class T> inline bool contains(const R& r, const T& v) { return std::find(boost::begin(r), boost::end(r), v) != boost::end(r); } /// determines if predicate evaluates to true for any value in container template<class R, class F> inline bool contains_if(const R& r, const F& f) { return std::find_if(boost::begin(r), boost::end(r), f) != boost::end(r); } /// insert elements in range r at end of container c template<class R, class C> inline void insert(C& c, const R& r) { c.insert(c.end(), boost::begin(r), boost::end(r)); } /// copy elements that match predicate template<class I, class O, class P> inline void copy_if(I i, I end, O& o, const P& p) { for (; i != end; ++i) { if (p(*i)) { *o = *i; ++o; } } } /// copy elements that match predicate template<class R, class O, class P> inline void copy_if(R& r, O& o, const P& p) { copy_if(boost::begin(r), boost::end(r), o, p); } /// erases first element that compare equal template<class C, class T> inline bool erase_first(C& c, const T& v) { typename C::iterator end = boost::end(c); typename C::iterator i = std::find(boost::begin(c), end, v); return i != c.end() ? c.erase(i), true : false; } /// erases first elements that match predicate template<class C, class F> inline bool erase_first_if(C& c, const F& f) { typename C::iterator end = boost::end(c); typename C::iterator i = std::find_if(boost::begin(c), end, f); return i != end ? c.erase(i), true : false; } /// erase all elements (doesn''t deallocate memory for std::vector) template<class C> inline void erase_all(C& c) { c.erase(c.begin(), c.end()); } /// erase all elements that compare equal template<typename C, typename T> int erase(C& c, const T& value) { int n = 0; for (boost::range_iterator<C>::type i = boost::begin(c); i != boost::end(c);) { if (*i == value) { i = c.erase(i); ++n; } else { ++i; } } return n; } /// erase all elements that match predicate template<typename C, typename F> int erase_if(C& c, const F& f) { int n = 0; for (boost::range_iterator<C>::type i = boost::begin(c); i != boost::end(c);) { if (f(*i)) { i = c.erase(i); ++n; } else { ++i; } } return n; } /// erases all consecutive duplicates from container (sort container first to get all) template<class C> inline int erase_duplicates(C& c) { boost::range_iterator<C>::type i = std::unique(c.begin(), c.end()); typename C::size_type n = std::distance(i, c.end()); c.erase(i, c.end()); return n; } /// erases all consecutive duplicates, according to predicate, from container (sort container first to get all) template<class C, class F> inline int erase_duplicates_if(C& c, const F& f) { boost::range_iterator<C>::type i = std::unique(c.begin(), c.end(), f); typename C::size_type n = std::distance(i, c.end()); c.erase(i, c.end()); return n; } /// fill but for the second value in each pair in range template<typename R, typename V> inline void fill_second(R& r, const V& v) { boost::range_iterator<R>::type i(boost::begin(r)), end(boost::end(r)); for (; i != end; ++i) { i->second = v; } } /// applying function to corresponding pair through both ranges, min(r1.size(), r2,size()) applications template<typename R1, typename R2, typename F> void for_each2(R1& r1, R2& r2, const F& f) { boost::range_iterator<R1>::type i(boost::begin(r1)), i_end(boost::end(r1)); boost::range_iterator<R2>::type j(boost::begin(r2)), j_end(boost::end(r2)); for(;i != i_end && j != j_end; ++i, ++j) { f(*i, *j); } } /// applying function to corresponding pair through both ranges, min(r1.size(), r2,size()) applications template<typename R1, typename R2, typename R3, typename F> void for_each3(R1& r1, R2& r2, R3& r3, const F& f) { boost::range_iterator<R1>::type i(boost::begin(r1)), i_end(boost::end(r1)); boost::range_iterator<R2>::type j(boost::begin(r2)), j_end(boost::end(r2)); boost::range_iterator<R3>::type k(boost::begin(r3)), k_end(boost::end(r3)); for(;i != i_end && j != j_end && k != k_end; ++i, ++j, ++k) { f(*i, *j, *k); } } /// applying function to each possible permutation of objects, r1.size() * r2.size() applications template<class R1, class R2, class F> void for_each_permutation(R1 & r1, R2& r2, const F& f) { typedef boost::range_iterator<R1>::type R1_iterator; typedef boost::range_iterator<R2>::type R2_iterator; R1_iterator end_1 = boost::end(r1); R2_iterator begin_2 = boost::begin(r2); R2_iterator end_2 = boost::end(r2); for(R1_iterator i = boost::begin(r1); i != end_1; ++i) { for(R2_iterator j = begin_2; j != end_2; ++j) { f(*i, *j); } } } template <class R> inline boost::iterator_range<boost::indirect_iterator<typename boost::range_iterator<R>::type > > make_indirect_range(R& r) { return boost::iterator_range<boost::indirect_iterator<typename boost::range_iterator<R>::type > > (r); } template <class R, class F> inline boost::iterator_range<boost::transform_iterator<F, typename boost::range_iterator<R>::type> > make_transform_range(R& r, const F& f) { return boost::iterator_range<boost::transform_iterator<F, typename boost::range_iterator<R>::type> >( boost::make_transform_iterator(boost::begin(r), f), boost::make_transform_iterator(boost::end(r), f)); } template <class T> inline boost::iterator_range<boost::counting_iterator<T> > make_counting_range(T begin, T end) { return boost::iterator_range<boost::counting_iterator<T> >( boost::counting_iterator<T>(begin), boost::counting_iterator<T>(end)); } template <class R, class F> inline boost::iterator_range<boost::filter_iterator<F, typename boost::range_iterator<R>::type> > make_filter_range(R& r, const F& f) { return boost::iterator_range<boost::filter_iterator<F, typename boost::range_iterator<R>::type> >( boost::make_filter_iterator(f, boost::begin(r), boost::end(r)), boost::make_filter_iterator(f, boost::end(r), boost::end(r))); } namespace detail { template<class T> T* get_pointer(T& p) { return &p; } } /// compare member function/variable equal to value. Create using @ref mem_eq() to avoid specfying types template<class P, class V> struct mem_eq_type { mem_eq_type(const P& p, const V& v) : m_p(p), m_v(v) { } template<class T> bool operator()(const T& a) const { using boost::get_pointer; using orz::detail::get_pointer; return (get_pointer(a)->*m_p) == m_v; } P m_p; V m_v; }; template<class P, class V> mem_eq_type<P,V> mem_eq(const P& p, const V& v) { return mem_eq_type<P,V>(p, v); } /// helper macro to define function objects that compare member variables of a class #define ORZ_COMPARE_MEMBER(NAME, OP) / template <class P> / struct NAME##_type / { / NAME##_type(const P&p) : m_p(p) {} / template<class T> / bool operator()(const T& a, const T& b) const { / return (a.*m_p) OP (b.*m_p); / } / P m_p; / }; / template <class P> / NAME##_type<P> NAME(const P& p) { return NAME##_type<P>(p); } #define ORZ_COMPARE_MEMBER_FN(NAME, OP) / template <class P> / struct NAME##_type / { / NAME##_type(const P&p) : m_p(p) {} / template<class T> / bool operator()(const T& a, const T& b) const { / return (a.*m_p)() OP (b.*m_p)(); / } / P m_p; / }; / template <class P> / NAME##_type<P> NAME(const P& p) { return NAME##_type<P>(p); } /// helper macro to wrap range functions as function objects (value return) #define ORZ_RANGE_WRAP_VALUE_2(FUNC, RESULT) / struct FUNC##_ / { / typedef RESULT result_type; / template<typename R, typename F> / inline RESULT operator() (R& r, const F& f) const / { / return FUNC(r, f); / } / }; /// helper macro to wrap range functions as function objects (void return) #define ORZ_RANGE_WRAP_VOID_2(FUNC) / struct FUNC##_ / { / typedef void result_type; / template<typename R, typename F> / inline void operator() (R& r, const F& f) const / { / FUNC(r, f); / } / }; /// helper macro to wrap range functions as function objects (void return, one argument) #define ORZ_RANGE_WRAP_VOID_1(FUNC) / struct FUNC##_ / { / typedef void result_type; / template<typename R> / inline void operator() (R& r) const / { / FUNC(r); / } / }; ORZ_RANGE_WRAP_VOID_2(for_each); ORZ_RANGE_WRAP_VOID_1(erase_all); ORZ_RANGE_WRAP_VALUE_2(contains, bool); ORZ_RANGE_WRAP_VALUE_2(contains_if, bool); ORZ_COMPARE_MEMBER(mem_equal, ==) ORZ_COMPARE_MEMBER(mem_not_equal, !=) ORZ_COMPARE_MEMBER(mem_less, <) ORZ_COMPARE_MEMBER(mem_greater, >) ORZ_COMPARE_MEMBER(mem_lessequal, <=) ORZ_COMPARE_MEMBER(mem_greaterequal, >=) ORZ_COMPARE_MEMBER_FN(mem_equal_fn, ==) ORZ_COMPARE_MEMBER_FN(mem_not_equal_fn, !=) ORZ_COMPARE_MEMBER_FN(mem_less_fn, <) ORZ_COMPARE_MEMBER_FN(mem_greater_fn, >) ORZ_COMPARE_MEMBER_FN(mem_lessequal_fn, <=) ORZ_COMPARE_MEMBER_FN(mem_greaterequal_fn, >=) #undef ORZ_COMPARE_MEMBER #undef ORZ_RANGE_WRAP_VALUE_2 #undef ORZ_RANGE_WRAP_VOID_1 #undef ORZ_RANGE_WRAP_VOID_2 }



El infame algoritmo de erase faltante:

template < class Container, class Value > void erase(Container& ioContainer, Value const& iValue) { ioContainer.erase( std::remove(ioContainer.begin(), ioContainer.end(), iValue), ioContainer.end()); } // erase template < class Container, class Pred > void erase_if(Container& ioContainer, Pred iPred) { ioContainer.erase( std::remove_if(ioContainer.begin(), ioContainer.end(), iPred), ioContainer.end()); } // erase_if


La función de utilidad en la caja de herramientas de everyones es por supuesto copy_if . Aunque no es realmente una envoltura.

Otro ayudante que uso comúnmente es el deleter , un funtor que uso con std::for_each para eliminar todos los punteros en un contenedor.

[edit] Explorando mi "sth.h" También encontré el vector<wstring> StringSplit(wstring const&, wchar_t);


La utilidad is_sorted , para probar contenedores antes de aplicar algoritmos como include que esperan una entrada ordenada:

template < class FwdIt > bool is_sorted(FwdIt iBegin, FwdIt iEnd) { typedef typename std::iterator_traits<FwdIt>::value_type value_type; return adjacent_find(iBegin, iEnd, std::greater<value_type>()) == iEnd; } // is_sorted template < class FwdIt, class Pred > bool is_sorted_if(FwdIt iBegin, FwdIt iEnd, Pred iPred) { if (iBegin == iEnd) return true; FwdIt aIt = iBegin; for (++aIt; aIt != iEnd; ++iBegin, ++aIt) { if (!iPred(*iBegin, *aIt)) return false; } return true; } // is_sorted_if

Sí, lo sé, sería mejor negar el predicado y usar la versión de predicado de adjacent_find :)


Mirando mi stl_util.h , muchos de los clásicos (funciones de eliminación, copy_if ), y también este (probablemente también bastante común, pero no lo veo dado en las respuestas hasta el momento) para buscar a través de un mapa y regresar ya sea el valor encontrado o predeterminado, ala get en el dict de Python:

template<typename K, typename V> inline V search_map(const std::map<K, V>& mapping, const K& key, const V& null_result = V()) { typename std::map<K, V>::const_iterator i = mapping.find(key); if(i == mapping.end()) return null_result; return i->second; }

El uso del valor null_result predeterminado de una V construida por defecto es muy similar al comportamiento del operator[] de std::map operator[] , pero esto es útil cuando el mapa es const (común para mí), o si el valor predeterminado es V no es lo correcto para usar


No es realmente un envoltorio, pero el infame copy_if faltante. De here

template<typename In, typename Out, typename Pred> Out copy_if(In first, In last, Out res, Pred Pr) { while (first != last) { if (Pr(*first)) { *res++ = *first; } ++first; } return res; }


Tengo un encabezado que pone lo siguiente en el espacio de nombres "util":

// does a string contain another string inline bool contains(const std::string &s1, const std::string &s2) { return s1.find(s2) != std::string::npos; } // remove trailing whitespace inline std::string &rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); return s; } // remove leading whitespace inline std::string &ltrim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); return s; } // remove whitespace from both ends inline std::string &trim(std::string &s) { return ltrim(rtrim(s)); } // split a string based on a delimeter and return the result (you pass an existing vector for the results) inline std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) { std::stringstream ss(s); std::string item; while(std::getline(ss, item, delim)) { elems.push_back(item); } return elems; } // same as above, but returns a vector for you inline std::vector<std::string> split(const std::string &s, char delim) { std::vector<std::string> elems; return split(s, delim, elems); } // does a string end with another string inline bool endswith(const std::string &s, const std::string &ending) { return ending.length() <= s.length() && s.substr(s.length() - ending.length()) == ending; } // does a string begin with another string inline bool beginswith(const std::string &s, const std::string &start) { return s.compare(0, start.length(), start) == 0; }


Ya no uso este tanto, pero solía ser un elemento básico:

template<typename T> std::string make_string(const T& data) { std::ostringstream stream; stream << data; return stream.str(); }

Se actualizará con más según los recuerdo. :PAG


boost::array

contiene (contenedor, val) (bastante simple, pero conveniente).

template<typename C, typename T> bool contains(const C& container, const T& val) { return std::find(std::begin(container), std::end(container), val) != std::end(container); }

remove_unstable (begin, end, value)

Una versión más rápida de std :: remove con la excepción de que no conserva el orden de los objetos restantes.

template <typename T> T remove_unstable(T start, T stop, const typename T::value_type& val){ while(start != stop) { if (*start == val) { --stop; ::std::iter_swap(start, stop); } else { ++start; } } return stop; }

(en el caso de un vector de tipos de vainas (int, float, etc.) y se eliminan casi todos los objetos, std :: remove puede ser más rápido).


Duplicate a string with *:

std::string operator*(std::string s, size_t n) { std::stringstream ss; for (size_t i=0; i<n; i++) ss << s; return ss.str(); }


I seem to need a Cartesian product, for example {A, B}, {1, 2} -> {(A,1), (A,2), (B,1), (B,2)}

// OutIt needs to be an iterator to a container of std::pair<Type1, Type2> template <typename InIt1, typename InIt2, typename OutIt> OutIt cartesian_product(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt out) { for (; first1 != last1; ++first1) for (InIt2 it = first2; it != last2; ++it) *out++ = std::make_pair(*first1, *it); return out; }


I would call such an append function by its name and would use operator+= , operator*= and so on for element-wise operations, such as:

template<typename X> inline void operator+= (std::vector<X>& vec1, const X& value) { std::transform( vec1.begin(), vec1.end(), vec1.begin(), std::bind2nd(std::plus<X>(),value) ); } template<typename X> inline void operator+= (std::vector<X>& vec1, const std::vector<X>& vec2) { std::transform( vec1.begin(), vec1.end(), vec2.begin(), vec1.begin(), std::plus<X>() ); }

some other simple and obvious wrappers as implied before:

template<typename X> inline void sort_and_unique(std::vector<X> &vec) { std::sort( vec.begin(), vec.end() ); vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() ); } template<typename X> inline void clear_vec(std::vector<X> &vec) { std::vector<X>().swap(vec); } template<typename X> inline void trim_vec(std::vector<X> &vec, std::size_t new_size) { if (new_size<vec.size()) std::vector<X>(vec.begin(),vec.begin() + new_size).swap(vec); else std::vector<X>(vec).swap(vec); }


IMO there needs to be more functionality for 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_


Insert a new item and return it, useful for simple move semantics like push_back(c).swap(value) and related cases.

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(); }

Pop and return an item:

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; }


Not sure if these qualify as std wrappers, but my commonly used helper functions are:

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 and V here are template arguments. The last function works the same way as []-operator, but with automating resizing to fit needed index.


One of my favorite is the Transposer that finds a transpose of a tuple of containers of the same size. That is, if you have a tuple<vector<int>,vector<float>> , it converts it into a vector<tuple<int, float>> . Comes handy in XML programming. Here is how I did it.

#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; }


Similar to what people posted before, I have convenience overloads of algorithms for simplifying passing iterator arguments. I call algorithms like this:

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

I overloaded all the algorithms such that they take a single parameter of type input_sequence_range<> instead of the two input iterators (input as in anything that isn''t mere output).

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) { } };

And this is how iseq() works:

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()); }

Similarly, I have specializations for

  • const_iterators
  • pointers (primitive arrays)
  • stream iterators
  • any range [begin,end) just for a uniform use: use iseq() for everything

Borrado desordenado para std::vector. La forma más eficiente de borrar un elemento de a, vectorpero no conserva el orden de los elementos. No veo el sentido de extenderlo a otros contenedores, ya que la mayoría no tienen la misma penalización por eliminar elementos del medio. Es similar a algunas otras plantillas ya publicadas pero se usa std::swappara mover elementos en lugar de copiar.

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 devuelve el signo de un tipo. Devuelve -1para negativo, 0para cero y 1para positivo.

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

La abrazadera se explica por sí misma, sujeta un valor para que se encuentre dentro del rango dado. Se perturba mi mente que la biblioteca estándar incluye miny maxaunque noclamp

template<typename T> T clamp(const T& value, const T& lower, const T& upper) { return value < lower ? lower : (value > upper ? upper : value); }


//! /brief Fills reverse_map from map, so that all keys of map // become values of reverse_map and all values become keys. //! /note This presumes that there is a one-to-one mapping in map! template< typename T1, typename T2, class TP1, class TA1, class TP2, class TA2 > inline void build_reverse_map( const std::map<T1,T2,TP1,TA1>& map , std::map<T2,T1,TP2,TA2>& reverse_map) { typedef std::map<T1,T2,TP1,TA1> map_type; typedef std::map<T2,T1,TP2,TA2> r_map_type; typedef typename r_map_type::value_type r_value_type; for( typename map_type::const_iterator it=map.begin(), end=map.end(); it!=end; ++it ) { const r_value_type v(it->second,it->first); const bool was_new = reverse_map.insert(v).second; assert(was_new); } }


template < class T > class temp_value { public : temp_value(T& var) : _var(var), _original(var) {} ~temp_value() { _var = _original; } private : T& _var; T _original; temp_value(const temp_value&); temp_value& operator=(const temp_value&); };

Ok, ya que parece que esto no es tan directo como pensé, aquí hay una explicación:
En su constructor temp_value almacena una referencia a una variable y una copia del valor original de la variable. En su destructor, restaura la variable referenciada a su valor original. Entonces, no importa lo que le haya hecho a la variable entre la construcción y la destrucción, se reiniciará cuando el objeto temp_value se salga del alcance.
Úselo así:

void f(some_type& var) { temp_value<some_type> restorer(var); // remembers var''s value // change var as you like g(var); // upon destruction restorer will restore var to its original value }

Aquí hay otro enfoque que usa el truco de alcance-guardia:

namespace detail { // use scope-guard trick class restorer_base { public: // call to flag the value shouldn''t // be restored at destruction void dismiss(void) const { mDismissed = true; } protected: // creation restorer_base(void) : mDismissed(false) {} restorer_base(const restorer_base& pOther) : mDismissed(pOther.is_dismissed()) { // take "ownership" pOther.dismiss(); } ~restorer_base(void) {} // non-virtual // query bool is_dismissed(void) const { return mDismissed; } private: // not copy-assignable, copy-constructibility is ok restorer_base& operator=(const restorer_base&); mutable bool mDismissed; }; // generic single-value restorer, could be made // variadic to store and restore several variables template <typename T> class restorer_holder : public restorer_base { public: restorer_holder(T& pX) : mX(pX), mValue(pX) {} ~restorer_holder(void) { if (!is_dismissed()) mX = mValue; } private: // not copy-assignable, copy-constructibility is ok restorer_holder& operator=(const restorer_holder&); T& mX; T mValue; }; } // store references to generated holders typedef const detail::restorer_base& restorer; // generator (could also be made variadic) template <typename T> detail::restorer_holder<T> store(T& pX) { return detail::restorer_holder<T>(pX); }

Es solo un poco más código de placa de caldera, pero permite un uso más limpio:

#include <iostream> template <typename T> void print(const T& pX) { std::cout << pX << std::endl; } void foo(void) { double d = 10.0; double e = 12.0; print(d); print(e); { restorer f = store(d); restorer g = store(e); d = -5.0; e = 3.1337; print(d); print(e); g.dismiss(); } print(d); print(e); } int main(void) { foo(); int i = 5; print(i); { restorer r = store(i); i *= 123; print(i); } print(i); }

Sin embargo, elimina su capacidad de ser utilizado en una clase.

Aquí hay una tercera forma de lograr el mismo efecto (que no sufre los problemas de potencialmente lanzar destructores):

Implementación:

//none -- it is built into the language

Uso:

#include <iostream> template <typename T> void print(const T& pX) { std::cout << pX << std::endl; } void foo(void) { double d = 10.0; double e = 12.0; print(d); print(e); { double f(d); double g(e); f = -5.0; g = 3.1337; print(f); print(g); e = std::move(g); } print(d); print(e); } int main(void) { foo(); int i = 5; print(i); { int r(i); r *= 123; print(r); } print(i); }


template <typename T> size_t bytesize(std::vector<T> const& v) { return sizeof(T) * v.size(); }

If you need to use a lot of functions that take pointer + number of bytes, it''s always just

fun(vec.data(), bytesize(vec));


template< typename T, std::size_t sz > inline T* begin(T (&array)[sz]) {return array;} template< typename T, std::size_t sz > inline T* end (T (&array)[sz]) {return array + sz;}