81 c++
今天早上问的这个问题让我想知道你认为C++标准库中缺少哪些功能,以及你如何用填充函数填补空白.例如,我自己的实用程序库具有此向量追加功能:
template <class T>
std::vector<T> & operator += ( std::vector<T> & v1,
const std::vector <T> & v2 ) {
v1.insert( v1.end(), v2.begin(), v2.end() );
return v1;
}
Run Code Online (Sandbox Code Playgroud)
这个用于清除(或多或少)任何类型 - 特别适用于像std :: stack这样的东西:
template <class C>
void Clear( C & c ) {
c = C();
}
Run Code Online (Sandbox Code Playgroud)
我还有一些,但我对你使用的是哪些感兴趣?请限制包装函数的答案- 即不超过几行代码.
Vik*_*ehr 37
包含(容器,val)(非常简单,但很方便).
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);
}
Run Code Online (Sandbox Code Playgroud)
remove_unstable(开头,结尾,值)
更快版本的std :: remove,但不保留其余对象的顺序.
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;
}
Run Code Online (Sandbox Code Playgroud)
(在pod类型的向量(int,float等)的情况下,几乎所有对象都被删除,std :: remove可能更快).
sbk*_*sbk 36
我经常使用向量作为一组项目,没有特定的顺序(显然,当我不需要快速is-this-element-in-the-set检查时).在这些情况下,调用erase()是浪费时间,因为它会重新排序元素,我不关心顺序.当下面的O(1)函数派上用场时 - 只需将最后一个元素移动到您想要删除的元素的位置:
template<typename T>
void erase_unordered(std::vector<T>& v, size_t index)
{
v[index] = v.back();
v.pop_back();
}
Run Code Online (Sandbox Code Playgroud)
sbi*_*sbi 26
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&);
};
Run Code Online (Sandbox Code Playgroud)
好吧,因为它似乎并不像我想象的那样直截了当,这里有一个解释:
在它的构造函数中temp_value存储对变量的引用和变量原始值的副本.在其析构函数中,它将引用的变量恢复为其原始值.因此,无论您对构造和销毁之间的变量做了什么,它都会在temp_value对象超出范围时重置.
像这样使用它:
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
}
Run Code Online (Sandbox Code Playgroud)
这是使用范围保护技巧的另一种方法:
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);
}
Run Code Online (Sandbox Code Playgroud)
这只是一个锅炉板代码,但允许更清洁的用法:
#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);
}
Run Code Online (Sandbox Code Playgroud)
但它删除了它在课堂上使用的能力.
这是实现相同效果的第三种方式(不会遇到可能抛出析构函数的问题):
执行:
//none -- it is built into the language
Run Code Online (Sandbox Code Playgroud)
用法:
#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);
}
Run Code Online (Sandbox Code Playgroud)
Gle*_*len 22
不是真正的包装纸,而是臭名昭着的缺失copy_if.从这里开始
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;
}
Run Code Online (Sandbox Code Playgroud)
sbi*_*sbi 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;}
Run Code Online (Sandbox Code Playgroud)
Inv*_*rse 12
有时候我觉得我在begin()和end()地狱.我想要一些功能,如:
template<typename T>
void sort(T& x)
{
std::sort(x.begin(), x.end());
}
Run Code Online (Sandbox Code Playgroud)
和其他类似的std::find,std::for_each基本上所有的STL算法.
我觉得sort(x)阅读/理解要快得多sort(x.begin(), x.end()).
我不再使用这个了,但它曾经是主食:
template<typename T>
std::string make_string(const T& data) {
std::ostringstream stream;
stream << data;
return stream.str();
}
Run Code Online (Sandbox Code Playgroud)
当我记住它们时会更新更新.:P
当然,每个人工具箱中的效用函数copy_if.虽然不是真正的包装.
我经常使用的另一个帮助是deleter,我用一个函子std::for_each来删除容器中的所有指针.
[编辑]挖掘我的"sth.h"我也发现了 vector<wstring> StringSplit(wstring const&, wchar_t);
我有一个标题,将以下内容放在"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 <rim(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;
}
Run Code Online (Sandbox Code Playgroud)
臭名昭着的遗漏erase算法:
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
Run Code Online (Sandbox Code Playgroud)
string example = function("<li value='%d'>Buffer at: 0x%08X</li>", 42, &some_obj);
// 'function' is one of the functions below: Format or stringf
Run Code Online (Sandbox Code Playgroud)
目标是将格式与输出分离,而不会遇到sprintf及其类似的麻烦.它不漂亮,但它非常有用,特别是如果您的编码指南禁止iostreams.
这是Neil Butterworth根据需要分配的版本.[查看Mike版本的修订历史记录,我将其作为剩余两个版本的子集删除.它类似于Neil,除了后者使用vector而不是delete []是异常安全的:string的ctor会抛出分配失败.迈克也使用后面显示的相同技术来预先确定尺寸.-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] );
}
Run Code Online (Sandbox Code Playgroud)
这是一个预先确定所需尺寸的版本,来自Roger Pate.这需要可写的std :: strings,它由流行的实现提供,但是C++ 0x明确要求.[查看Marcus版本的修订历史记录,我将其删除,因为它略有不同,但基本上是下面的一部分.-RP]
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);
}
Run Code Online (Sandbox Code Playgroud)
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, ...);
Run Code Online (Sandbox Code Playgroud)
该is_sorted实用程序,用于在应用include期望已排序条目的算法之前测试容器:
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
Run Code Online (Sandbox Code Playgroud)
是的,我知道,最好否定谓词并使用谓词版本adjacent_find:)
| 归档时间: |
|
| 查看次数: |
9584 次 |
| 最近记录: |