Which C++ Standard Library wrapper functions do you use?
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 - ie no more than a couple of lines of code.
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).
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();
}
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);
}
链接地址: http://www.djcxy.com/p/72970.html
上一篇: 什么是使用C ++ 11范围的正确方法
下一篇: 您使用哪种C ++标准库包装函数?