65.9K
CodeProject 正在变化。 阅读更多。
Home

Boost.Range 对 ATL/WTL CString 的支持

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.12/5 (9投票s)

2005 年 9 月 2 日

2分钟阅读

viewsIcon

37058

downloadIcon

262

使用 Boost.Range 为 CString 提供一致的接口。

引言

Tomato.String 为 ATL/WTL CString 提供 Boost.Range 支持。 CString 不能是 Sequence 的模型,因为 Sequence 的需求是使用成员函数定义的。但是 Boost.Range 的概念有些新,并且是使用自由(非成员)函数定义的。 因此,通过使用本文,您可以将 CString 传递给任何接受 Random Access Range 的算法。

要求

快速开始

  1. 包含头文件
    #include "ketchup/tomato/string.hpp"
  2. 调用算法
    #include <boost/algorithm/string.hpp>
    
    void quick_start()
    {
      WTL::CString str(_T("hello range!"));
      boost::to_upper(str);
      ATLASSERT( str == _T("HELLO RANGE!") );
    }

我将介绍一些 ATL/WTL CString 可以使用的算法。

Boost.String 算法

Boost.StringAlgorithm 运作良好

#include <boost/algorithm/string.hpp>

void test_string_algo()
{
  ATL::CFixedStringT<ATL::CString, 50> str(_T("123xxx321"));

  ATLASSERT( boost::starts_with(str, _T("123")) );
  ATLASSERT( !boost::starts_with(str, _T("1234")) );
}

tomato::back_inserter

由于 ATL/WTL CString 无法符合 Sequence,因此您无法直接替换 CString 的字符。 但是您有 Output Iterator

#include "ketchup/tomato/iterator.hpp"

void test_back_inserter()
{
  ATL::CString strout;
  boost::replace_first_copy( tomato::back_inserter(strout), 
                      _T("1abc3abc2"), _T("abc"), _T("YYY"));
  ATLASSERT( strout == _T("1YYY3abc2") ); 
}

tomato::back_inserter 接受像 std::string 这样的 Back Insertion Sequence

STL 算法

STL 算法也能很好地工作。由于 STL 不知道 Boost.Range 的概念,您需要 Boost.Range 函数包含的 boost::beginend 的帮助

#include <algorithm>
#include <boost/range.hpp>

void test_std_algo()
{

  WTL::CString str(_T("acbfdge"));
  std::sort(boost::begin(str), boost::end(str));
  ATLASSERT( str == _T("abcdefg") );
}

所有接受 Random Access Iterator 的算法都可以工作。 请记住,Boost.Range 函数是 Container 的相应成员的替代品。 从现在开始,您不应使用诸如 GetBufferGetStringbegin 之类的成员。

Boost.Regex

Boost.Regex 已经 支持 ATL::CString,但是我支持的 WTL::CString 缺失了

#include <boost/regex.hpp>
// for boost::tregex
#include <boost/regex/mfc.hpp>

void test_regex()
{
  WTL::CString str(_T("123a1cxxxa23cXXXa456c321"));
  boost::tregex rx(_T("a([0-9]+)c"));
  WTL::CString fmt(_T("_A$1C_"));

  WTL::CString strout = boost::regex_replace(str, rx, fmt);
  ATLASSERT( boost::equals( strout, 
                   _T("123_A1C_xxx_A23C_XXX_A456C_321")) );
}

另一种方法是使用 Boost.StringAlgorithm 提供的薄封装

#include <string>
// yet required
#include <boost/algorithm/string/regex.hpp>
// for boost::tregex
#include <boost/regex/mfc.hpp>

void test_algo_regex()
{
  // works around missing overloads
  typedef std::basic_string<TCHAR> fmt_string_t; 

  ATL::CString str(_T("123a1cxxxa23cXXXa456c321"));
  boost::tregex rx(_T("a([0-9]+)c"));
  fmt_string_t fmt(_T("_A$1C_"));

  WTL::CString strout;
  boost::replace_regex_copy( tomato::back_inserter(strout), 
                                              str, rx, fmt );
  ATLASSERT( boost::equals( strout, 
                         _T("123_A1C_xxxa23cXXXa456c321")) );
}

关注点

为什么 CString 应该符合 Boost.Range 概念? 现在我们有三种字符串类型:std::stringATL::CStringWTL::CString,在编写自己的算法时您会选择哪一个? 您会像可怜的 WTL 一样定义 _CSTRING_NS 吗? Boost.Range 解决了这些问题。

顺便说一句,为什么我们要为 STL 算法编写数百个 beginendBoost.RangeEx(非官方)提供了薄封装函数

#include <boost/range_ex/algorithm.hpp>

void test_range_algo()
{
  WTL::CString str(_T("acbfdge"));
  boost::sort(str);
  ATLASSERT( str == _T("abcdefg") );
}

参考文献

发行说明

  • 0.90.0 版 - 初始版本。
© . All rights reserved.