83

This question, asked this morning, made me wonder which features you think are missing from the C++ Standard Library, and how you have gone about filling the gaps with wrapper functions. For example, my own utility library has this function for 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;
}

and this one for clearing (more or less) any type - particularly useful for things like std::stack:

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

I have a few more, but I'm interested in which ones you use? Please limit answers to wrapper functions - i.e. no more than a couple of lines of code.

Community
  • 1
  • 1
  • 11
    Does it count that I wrapped most of the STL algorithm to act on whole containers instead of ranges, just because messing with the iterators is just so common a mistake :) ? – Matthieu M. Mar 31 '10 at 13:05
  • @Matthieu M.: What exactly is the common mistake? If you don't understand how the standard algorithms work with iterators then you really need to read an STL book before playing with it. – Billy ONeal Mar 31 '10 at 13:10
  • @BillyONeal: the common mistake is confusing whether an algorithm takes one or two iterators to a container, especially when the algorithm works on multiple containers. – MSalters Mar 31 '10 at 13:30
  • @BillyONeal: The common mistake is to mess up the iterators and end up with two which don't denote a range (for example, because they point into different sequences). Or, for the algorithms taking iterators into several sequences (`insert()`) to mess up the order. Or one of the other very common gotchas that happen when you have to carry around two objects for one concept. (Why do you think that concept called "ranges" crops up everywhere the STL is discussed?) – sbi Mar 31 '10 at 14:12
  • @Beau Martínez: That's why it's a CW. – Billy ONeal Mar 31 '10 at 14:35
  • 2
    @Billy actually, CW is not really an excuse for asking subjective questions. I'll change the title, which should keep people happy. –  Mar 31 '10 at 14:40
  • @BillyONeal My point is, how many questions have you seen that have been closed for being 'subjective'? – Humphrey Bogart Mar 31 '10 at 14:43
  • Shouldn't your 1st function call `v1.reserve( v1.size()+v2.size() )` to avoid multiple possible resizes during your append loop? – KitsuneYMG Mar 31 '10 at 15:00
  • 1
    @kts What "append loop"? –  Mar 31 '10 at 15:01
  • 4
    @kts: Since vector::insert is given random-access iterators, a good implementation will use compile-time dispatch to do that itself. –  Mar 31 '10 at 15:43
  • 2
    Duplicate: [What is your most useful C/C++ snippet?](http://stackoverflow.com/questions/469696/) –  May 18 '10 at 04:54
  • @Neil: Wrapper functions are snippets, especially when "no more than a couple of lines of code". –  May 24 '10 at 00:13
  • 4
    Isn't it better to write `c.swap(C())` to clear a container ? – Alexandre C. Jul 19 '10 at 09:15
  • 5
    @Alexandre: That isn't allowed: it binds a temporary to a non-const ref. C().swap(c) would work. –  Oct 05 '10 at 00:39

26 Answers26

39

Quite often I'd use vector as a set of items in no particular order (and, obviously, when I don't need fast is-this-element-in-the-set checks). In these cases, calling erase() is a waste of time since it will reorder the elements and I don't care about order. That's when the O(1) function below comes in handy - just move the last element at the position of the one you'd want to delete:

template<typename T>
void erase_unordered(std::vector<T>& v, size_t index)
{
    v[index] = v.back();
    v.pop_back();
}
sbk
  • 9,212
  • 4
  • 32
  • 40
  • Good one. Hadn't thought about doing it like that.. :) There ought to be a 'Bag' wrapper (similar to stack and queue) that speeds up these ops when order isn't important. – Macke Mar 31 '10 at 15:05
  • 13
    And in C++0x, `v[index] = st::move(v.back()); v.pop_back();` is about as efficient as it gets. – GManNickG Mar 31 '10 at 20:14
  • @Matthieu: Look at the time stamp on those. :P I noticed a couple hours later, far past the allowed editing time. – GManNickG Apr 01 '10 at 14:18
  • @GMan: are you sure about this? looks to me like v.pop_back() might result in undefined behavior as the destructor will be called. – Viktor Sehr Jul 27 '10 at 19:11
  • 1
    @Viktor: Move-semantics don't mean "I take your resources and that's that", they mean "I take your resources and put you in a no-resource state." In other words, your move semantics need to make sure the object can safely destruct; pretty easy to do, just set pointers to null. – GManNickG Jul 27 '10 at 19:15
  • @GMan: Ah, ok. I thought it only took the resources – Viktor Sehr Jul 27 '10 at 20:50
  • @Viktor: Yeah, I did too. I even [asked a question](http://stackoverflow.com/questions/2142965/c0x-move-from-container) (prior to this answer, hence I was confident about my comment above). It seems a bit scary at first, but if you keep in mind moved objects *must* be valid, it goes away. :) – GManNickG Jul 27 '10 at 21:34
  • @GMan: I hope the compiler are able to optimize away destructor calls, i.e; `Class x; Class y = std::move(x);` means the destructor of x will not be called when going out of scope. Otherwise, I am against making them valid =) – Viktor Sehr Jul 28 '10 at 08:12
  • @Viktor: No, automatically allocated objects *must* have their destructor called, period. :) Optimization is an implementation-specific detail, C++ does not require or touch on any of that stuff. (Likely, a compiler will. Indeed, I [even go through an example (bottom)](http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom) of how a compiler uses move-semantics to optimize `std::swap` into the most efficient `swap` possible.) But you are required to keep the object in a valid state, per the standard. – GManNickG Jul 28 '10 at 08:25
  • move semantics doesn't guarantee O(1) or any better performance than copy. you think you can move `std::array` all over the place that easily ? – v.oddou Nov 18 '14 at 07:48
38

boost::array

contains(container, val) (quite simple, but convenient).

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)

A faster version of std::remove with the exception that it doesn't preserve the order of the remaining objects.

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

(in the case of a vector of pod types (int, float etc) and almost all objects are removed, std::remove might be faster).

Marc Mutz - mmutz
  • 24,485
  • 12
  • 80
  • 90
Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
  • 4
    Does anyone else think that contains needs a third template (`bool sorted=false`) and a specialization when `sorted==true` to call `binary_search` instead of `find`? – KitsuneYMG Mar 31 '10 at 15:05
  • 7
    @kts: When you know *container* is sorted, just call *binary\_search* directly. –  Mar 31 '10 at 15:13
  • 2
    boost::array STL equivalent is available in the tr1 namespace on most recent compilers (even codewarrior) : std::tr1::array<> – Klaim Apr 21 '10 at 09:06
28
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, since it seems this isn't as straight-forward as I thought, here's an explanation:
In its constructor temp_value stores a reference to a variable and a copy of the variable's original value. In its destructor it restores the referenced variable to its original value. So, no matter what you did to the variable between construction and destruction, it will be reset when the temp_value object goes out of scope.
Use it like this:

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
}

Here's another approach that uses the scope-guard trick:

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

It's just a bit more boiler-plate code, but allows a cleaner usage:

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

It removes its ability to be used in a class, though.


Here's a third way to achieve the same effect (which doesn't suffer from the problems of potentially throwing destructors):

Implementation:

//none -- it is built into the language

Usage:

#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);
}
Mankarse
  • 39,818
  • 11
  • 97
  • 141
sbi
  • 219,715
  • 46
  • 258
  • 445
22

Not really a wrapper, but the infamous missing copy_if. From 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;
}
Glen
  • 21,816
  • 3
  • 61
  • 76
  • 2
    Doesn't answer the question, not a wrapper for the stdlib. –  Apr 02 '10 at 20:51
  • 10
    @Roger Pate, yes I know, that's why the answer begins with the words "Not really a wrapper, but....". – Glen Apr 02 '10 at 22:03
  • 1
    @Roger implementation detail. If you really wish you can implement it in terms of `remove_copy_if()`. :p – wilhelmtell Apr 21 '10 at 02:55
18
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;}
sbi
  • 219,715
  • 46
  • 258
  • 445
  • 2
    I have these too. :) +1 For what it's worth, you only need two (ditch the const versions). When the array is const, `T` will be `const U` and you get the intended function. – GManNickG Mar 31 '10 at 14:52
  • @GMan: There was some version of GCC which wouldn't compile some code with only the non-`const` versions, that's why the `const` versions are there. Since that might have been a bug of that particular GCC version, I will remove them. – sbi Mar 31 '10 at 16:05
  • 1
    @Marcus: These are far older than Boost.Range. `:)` – sbi Mar 31 '10 at 16:06
  • Doesn't answer the question; not a wrapper for the stdlib. –  Apr 02 '10 at 20:52
  • 4
    @Roger: It wraps arrays for them to be used with the standard lib. There you go. `:)` – sbi Jun 02 '10 at 10:58
  • @sbi: If there was a template in the stdlib that used begin(some_obj), that would make sense. (There is in 0x, plus the ranged-for loop, but then there's std::begin for that.) Not a big deal, this question is a dupe anyway. –  Jun 02 '10 at 11:28
  • Is the array parameter passed by value (resulting in a copy)? – StackedCrooked Apr 28 '11 at 15:51
  • @Stacked: No. That's what the `&` is for. – sbi Apr 28 '11 at 17:33
  • 2
    @Stacked, @sbe: Arrays are never passed by value, regardless of whether or not there is an `&`. The `&` is there to enable type deduction of the length of the array. – Mankarse Jun 03 '11 at 14:42
12

Sometimes I feel like I'm in begin() and end() hell. I'd like to have some functions like:

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

and other similar ones for std::find, std::for_each, and basically all the STL algorithms.

I feel that sort(x) is much quicker to read/understand than sort(x.begin(), x.end()).

Inverse
  • 4,408
  • 2
  • 26
  • 35
  • 1
    hint; use ´sort(boost::begin(x), boost:end(x));´ instead, and youre able to sort arrays aswell. – Viktor Sehr Apr 26 '10 at 21:33
  • 4
    [Boost.Range](http://www.boost.org/doc/libs/release/libs/range/index.html) v2 has adapters like this for the entire standard library. – ildjarn May 11 '11 at 19:48
9

I don't use this one nearly as much anymore, but it used to be a staple:

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

Will update with more as I remember them. :P

Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
9

The utility function in everyones toolbox is of course copy_if. Not really a wrapper though.

Another helper I commonly use is deleter, a functor I use with std::for_each to delete all pointers in a container.

[edit] Digging through my "sth.h" I also found vector<wstring> StringSplit(wstring const&, wchar_t);

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • +1 for deleter functors. My deleter functor works well with most containers, however I've been playing around with getting it to work with std::map's where either the key or value is a pointer. I tried using type traits to solve the problem, but didn't really get very far due to time constraints. Have you solved this issue or do you consider it an issue? – Glen Mar 31 '10 at 12:50
  • 2
    @Matthieu M. not all of us can use boost, unfortunately. – Glen Mar 31 '10 at 13:24
  • @Glen: All these troubles can be solved by using smart pointers, preferably (but not necessarily) from boost. As an important side effect, containers with pointers to dynamically allocated objects suddenly become exception safe, too. – sbi Mar 31 '10 at 13:36
  • @Glen here, here for projects which stipulate no libraries other than the STD, up to and including Boost or TR1. – wheaties Apr 02 '10 at 02:03
  • 7
    @the unfortunate victims of corporate stupidity: get an exception for in-house libraries, then import the useful parts of Boost into the in-house library. Even in politics all problems can be solved with another level of indirection. – MSalters Apr 06 '10 at 09:56
9

I have a header which puts the following in the "util" namespace:

// 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;
}
Evan Teran
  • 87,561
  • 32
  • 179
  • 238
  • 2
    That `split()` swallows any errors occurring in `std::getline()`, silently returning a vector that's too short. – sbi Apr 01 '10 at 12:30
  • of course, you should check the `size()` of result before retrieving your strings. – Evan Teran Apr 01 '10 at 14:48
  • And how would I know how many strings the result ought to have? – sbi Apr 01 '10 at 17:08
  • depends on your use case of course. If you have a well formatted line based input file, then this will work nicely. If you are grabbing random data from anywhere, you'll likely need something more robust that will report if `std::getline` encountered an error. Though I'm not sure that there are many ways `std::getline` can fail when operating on a `std::stringstream` what types of errors are you considering here? Obviously the streams bad/fail bits can get set, but by what? What input could cause it to fail? – Evan Teran Apr 01 '10 at 18:55
  • 2
    @sbi: Your comment has peaked my interest about what actually could go wrong (aside from the string simply not having enough tokens to get) with the `stringstream`/`getline` loop. I've posed a question about it here: http://stackoverflow.com/questions/2562906/ways-stdstringstream-can-set-fail-bad-bit – Evan Teran Apr 01 '10 at 19:05
  • 2
    @Evan: I stand corrected. See my comment at http://stackoverflow.com/2563542#2563542. Sorry. – sbi Apr 02 '10 at 08:20
8

The infamously missing erase algorithm:

  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
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • +1, was about to post mine exact equivalent. Altough I've named it remove_erase(...) – Viktor Sehr Mar 31 '10 at 13:04
  • 2
    The only problem with this is that it breaks the semantic erase-remove idiom expected in the STL. You need the erase-remove idiom with *any* algorithm that has remove semantics -- not just `std::remove`. For example, `std::unique`. – Billy ONeal Mar 31 '10 at 13:12
  • Well, I have containers adaptations of most STL algorithms for this :) But this is the one I use the most, usually if I want uniqueness I use a `set` to begin with. – Matthieu M. Mar 31 '10 at 13:24
  • @Matthieu M.: Just keep in mind by doing this you're going to have people who work with the STL all the time having alarm bells going off in their heads "WARNING: REMOVE-LIKE ALGORITHM WITH NO CALL TO ERASE!!". There's nothing wrong with it really, but it's not something I'd do if I needed to share my code among many programmers. Just my 2 cents. – Billy ONeal Mar 31 '10 at 20:10
  • 1
    @Billy: that's why I called it erase and not remove. There's not much I can do besides that apart from letting them consult the code. Thankfully with modern IDE the definition is just a click away :) – Matthieu M. Apr 01 '10 at 06:18
  • This can can be expensive, particularly if you need to add elements to the container after calling `erase()`. I prefer the remove-erase idiom precisely because it is more verbose: it can be expensive. – wilhelmtell Apr 21 '10 at 03:44
7

Wrapping 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

The goal is decoupling formatting from output without getting into trouble with sprintf and its ilk. It's not pretty, but it's very useful, especially if your coding guidelines ban iostreams.


Here is a version which allocates as needed, from Neil Butterworth. [View revision history for Mike's version, which I removed as a subset of the remaining two. It is similar to Neil's, except the latter is exception-safe by using vector instead of delete[]: string's ctor will throw on allocation failure. Mike's also uses the same technique shown later to determine size up front. –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] );
}

Here is a version which determines the needed size up front, from Roger Pate. This requires writable std::strings, which are provided by popular implementations, but are explicitly required by C++0x. [View revision history for Marcus' version, which I removed as it is slightly different but essentially a subset of the below. –RP]

Implementation

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

Public interface

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, ...);
Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96
  • @Neil: From `man vsnprintf`: "These functions return the number of characters printed ... or a negative value if an output error occurs, **except** for `snprintf()` and `vsnprintf()`, which return the number of characters that would have been printed if the n were unlimited ..." Hence the dummy call with a 0 buffer to measure out the needed buffer size. – Mike DeSimone Mar 31 '10 at 19:29
  • @Checkers: Ah, Boost. Such great potential that they won't let me use either. Someday, hopefully. Anyway, has Boost gotten big enough to be impossible to fully understand yet? I'd be happy just to get `boost::spirit`. – Mike DeSimone Mar 31 '10 at 19:31
  • This is actually Windows code - from MSDN "For _vsnprintf, if the number of bytes to write exceeds buffer, then count bytes are written and –1 is returned." but I do port it it to Linux. I can't remember if my Linux app actually uses this, or if I've tested it for large buffer sizes there - must do so. Thanks. –  Mar 31 '10 at 19:35
  • 1
    if you use Windows code anyway, go ahead and use `_vscprintf` to determine the needed size of the buffer. – smerlin Mar 31 '10 at 23:20
6

The is_sorted utility, to test containers before applying algorithms like include which expect a sorted entry:

  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

Yeah, I know, would be better to negate the predicate and use the predicate version of adjacent_find :)

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
3

Definitely boost::addressof

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Actually, I've heard a lot of discussions about overloading &, but I've never, ever seen anyone actually do it (hmm bit_reference maybe). – Viktor Sehr Apr 26 '10 at 21:35
  • @Victor Sehr: ATL::CComPtr (http://msdn.microsoft.com/en-us/library/ezzw7k98(VS.80).aspx) and _com_ptr_t (http://msdn.microsoft.com/en-us/library/417w8b3b(VS.80).aspx) are good examples. – sharptooth Apr 27 '10 at 05:05
3
//! \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);
    }
}
sbi
  • 219,715
  • 46
  • 258
  • 445
  • I prefer using the `Boost.Bimap` library (or `Boost.MultiIndex` for more complex situations) – Matthieu M. Mar 31 '10 at 13:01
  • 1
    I dont get it, why the assert()? – Viktor Sehr Mar 31 '10 at 13:07
  • @Viktor: to ensure there are no duplicated keys in `reverse_map`. Consider `map` has (1->"one"; 2->"one") `reverse_map` will get one element ("one"->1). The assert will catch that. See also: bijection – sbk Mar 31 '10 at 13:35
  • @Viktor: Because the original map might have the same value for several keys. Since the values end up as keys in the reversed map, this would be fatal. – sbi Mar 31 '10 at 13:38
  • 3
    Btw, sbi, having code with side effects within an assert() will bite you pretty bad once you compile with NDEBUG and assert()s are stripped altogether. – sbk Mar 31 '10 at 13:39
  • @sbk: Nice catch. The original code uses a special version of assert that disregards `NDEBUG`, which just replaced for posting here without thinking. I'll change this. – sbi Mar 31 '10 at 13:41
  • @sbk\@sbi: I got that, but when the whole scope was in the assert, I didnt understand if this function was only used to assert there were no duplicates in the values – Viktor Sehr Mar 31 '10 at 19:21
  • 2
    gah, after the update my first comment looks really stupid, stackoverflow is #1 when googling my name so I hope no future employer sees this =) – Viktor Sehr Mar 31 '10 at 19:31
  • @Viktor: The blame is all mine. I blew it when I changed it for posting it here. – sbi Apr 02 '10 at 15:56
  • in this form there will be a warning when the assert is compiled to emptiness. because of an unused variable. – v.oddou Nov 18 '14 at 07:43
  • @v.oddou: Indeed. In reality, this code was part of a proprietary framework and used that framework's assertion macro which made sure the side effect would always take place, so the original code was `MY_ASSERT(reverse_map.insert(v).second)`. This cannot be done with `assert()` from the C std lib, so I fixed this when I posted it. But overlooked that the fix would cause a warning. `:(` – sbi Nov 18 '14 at 19:17
  • @sbi: obviously its OK because this is not production code. Simply, I recognize these kinds of construct easily because they are kind of recurrent :) Mentionning it here is useful since it can educate beginners about the effects of macro-toggled conditional builds. – v.oddou Nov 19 '14 at 01:58
3

Looking at my stl_util.h, many of the classics (deleter functions, copy_if), and also this one (probably also quite common, but I don't see it given in the responses so far) for searching through a map and returning either the found value or a default, ala get in Python's dict:

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

Using the default null_result of a default-constructed V is much as same as the behavior of std::map's operator[], but this is useful when the map is const (common for me), or if the default-constructed V isn't the right thing to use.

Jack Lloyd
  • 8,215
  • 2
  • 37
  • 47
3

Here's my set of extra-utils, built on top of a boost.range'ish std-algo wrapper that you might need for some functions. (that's trivial to write, this is the interesting stuff)

#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
}
Macke
  • 24,812
  • 7
  • 82
  • 118
  • +1 for *for_each_permutation(...)*, mainly because I've written a similar wrapper =). But why does *erase_duplicates(...)* return a signed int? – Viktor Sehr Mar 31 '10 at 19:29
  • Hi Viktor! You ought to have seen *for_each_permutation* at your previous job too, I think. ;) *erase_duplicates* returns the number of erased elements, which is useful for logging & debugging. – Macke Apr 01 '10 at 14:51
  • Hmm might have browsed over it not realizing what it does *;)*, anyway, I get why it returns an integer, I just dont get why the integer is signed (or to be more specific; *why is it not unsigned*)? – Viktor Sehr Apr 03 '10 at 15:24
  • Ah. Just lazyiness on my part :-P. size_t is the appropriate type. – Macke Apr 03 '10 at 19:01
3

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;
}
rlbond
  • 65,341
  • 56
  • 178
  • 228
  • Note that InIt2 must be a [forward iterator](http://www.sgi.com/tech/stl/ForwardIterator.html) instead of an input iterator. Input iterators are not suitable for multiple passes. –  Apr 25 '10 at 16:27
2

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);
    }
Dane
  • 133
  • 1
  • 11
  • 7
    These operators are a very good example why operator overloading should be done rarely. I would have thought, `vec+=val` would _append_ a value to the vector. (See http://stackoverflow.com/questions/2551775/.) Now that I have seen your implementation, I think this is just as right an interpretation of the meaning of `+=`, too. I wouldn't know which one would be right or wrong, so it's probably just as well that we don't have `+=` for `std::vector`. – sbi Apr 02 '10 at 16:02
  • 1
    @sbi I agree. I find `operator+()` missing an amazing early insight of the standard. I usually expect an O(1) operation everywhere I see the plus operator. C++ makes things that are expensive or dangerous more verbose or difficult to do, and I like it this way. Take a look at Java: one of the worst coding mistakes there is the abuse of the plus operator. Of course, then again, C++ doesn't always make cheap and fast things easy, but hey. Good C++ programmers are very much performance-aware. ;) – wilhelmtell Apr 21 '10 at 06:04
  • 2
    I agree with both of you that `op+()` shouldn't be defined at all due to its ambiguity. But vectors are usually part of an (mathematical) vector space and there is a canonical definition of adding two vectors and scalar multiplication. To take your argument further: a simple `double` is a vector as well, so if you'd add two `double` variables like `a+b` then you'd expect to get a new `double` and not a `pair` of double like `(a,b)`. Multiplying with a scalar is canonical too, but multiplying two vectors is not. So overloading should be done with care.. – Dane Jun 10 '10 at 06:50
1
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));
hrehfeld
  • 470
  • 1
  • 4
  • 14
1

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();
}
kirbyfan64sos
  • 10,377
  • 6
  • 54
  • 75
1

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

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_
rlbond
  • 65,341
  • 56
  • 178
  • 228
  • 1
    Why not move the `PairType` template to operator()? Also, the double-underscores in the identifier are reserved. – GManNickG Apr 21 '10 at 00:37
  • @GMan - Because then you can't use `unary_function`, which I need at some point in my code. As for the double-underscores, thanks for letting me know -- I'll need to change that. – rlbond Apr 21 '10 at 15:55
  • This uses dependent names (argument_type, result_type) incorrectly, and compilers are required to reject it. "In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member." [14.6.2/3, C++03] –  Apr 25 '10 at 20:39
  • @Roger Pate: I was unaware of that rule. It's fixed now. – rlbond Apr 26 '10 at 05:06
0

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;
}
Sumant
  • 4,286
  • 1
  • 23
  • 31
0

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.

AareP
  • 2,355
  • 3
  • 21
  • 28
  • 1
    The name 'assert' is reserved (in all scopes) by the standard library for its macro of that name. –  Apr 02 '10 at 00:07
  • 1
    I think there's also an assert() macro declared in windows or mfc headers. Both of them fail in WM_PAINT event, because displaying assertion dialog triggers next assestion in some cases. So in the end, it's not a big deal to replace those buggy implementations with a third one. All you have to do is explicitly redeclare own assert-macro after #include , or just use #undef assert. – AareP Apr 03 '10 at 09:17
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
wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
  • 3
    ...or you could just use Boost.Range and get the benefits of range adaptors and peer reviewed, widely tested code. – Mankarse Jun 03 '11 at 14:54
0

Unordered erase for std::vector. The most efficient way to erase an element from a vector but it does not preserve the order of elements. I didn't see the point of extending it to other containers since most don't have the same penalty for removing items from the middle. It's similar to some other templates already posted but it uses std::swap to move items instead of copying.

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 returns the sign of a type. Returns -1 for negative, 0 for zero and 1 for positive.

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

Clamp is pretty self explanatory, it clamps a value so that it lies within the given range. It boggles my mind that the Standard Library includes min and max but not clamp

template<typename T>
T clamp(const T& value, const T& lower, const T& upper)
{
    return value < lower ? lower : (value > upper ? upper : value);
}
Fibbs
  • 1,350
  • 1
  • 13
  • 23