荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: sephiroth (Dreams Come True), 信区: Program
标  题: C++技巧:将算符和函数同时保存在一个数组[转载]
发信站: 荔园晨风BBS站 (Fri Jan  3 21:45:15 2003), 站内信件


在标准模板库(STL)中,算符是经常使用而又新推出的一个概念。一个算符即是具
有函数特性的对象。既然它作为一个对象,算符包括内容,以及与算符相关联的东
西。


由于能够被赋予一定数量的元素,算符和函数非常有用。开发人员在编程过程中通
常需要把多个转换结果传递给一定范围的元素。其中一些转换属于函数,一些转换
属于算符。然而,要把函数和算符同时保存一个数组是不可能的,因为函数和算符
不能共用一个基类。

我们可以通过生成一个封装类来解决以上的问题,这一封装类既包括函数又包括算
符。你可以使用任一容器来容纳它们,包括STL容器或象C中的数组。

保存在数组中的每一个函数/算符需要一个传入参数并返回一个值。这是因为函数
/算符被赋予一个元素并返回一个值。

下面即是一个范例,这一范例能够将多种转换结果赋予一个字符串的数组。

#include
<string>
#include <functional>
#include <deque>
#include <iostream>

// truncates a string - you pass the max. nr. of chars a string can
have;
// then, for each string you pass,
// it returns a string with the nr. of chars <= max. nr. of chars
class truncate_string
  : public std::unary_function< const std::string &,std::string>
{
public:
  truncate_string( int nMaxChars)
    : m_nMaxChars( nMaxChars) {}
  std::string operator()( const std::string & strSource)
  {
    std::string strTruncated = strSource.substr( 0,m_nMaxChars);
    return strTruncated;
  }
private:
  int m_nMaxChars;
};

// surrounds a string - with the two chars you pass at construction
class surround_string
  : public std::unary_function< const char *, std::string>
{
public:
  surround_string( char chFirst, char chLast)
    : m_chFirst( chFirst), m_chLast( chLast) {}
  std::string operator()( const char * strSource)
  {
    std::string strSurrounded;
    strSurrounded += m_chFirst;
    strSurrounded += strSource;
    strSurrounded += m_chLast;
    return strSurrounded;
  }
private:
  char m_chFirst;
  char m_chLast;
};


std::string first_half( const char * strSource)
{
  std::string strHalf = strSource;
  size_t nLen = strHalf.length();
  nLen = (nLen + 1) / 2;
  strHalf = strHalf.substr( 0, nLen);
  return strHalf;
}

std::string second_half( const char * strSource)
{
  std::string strHalf = strSource;
  size_t nHalfLen = strHalf.length() / 2;
  strHalf = strHalf.substr( nHalfLen);
  return strHalf;
}

// trims leading & trailing spaces
std::string trim( const std::string & strSource)
{
  int nLen = ( int)strSource.length();
  int idxFirst = 0;
  int idxLast = nLen - 1;
  while ( (idxFirst < nLen) && isspace( strSource[idxFirst]))
  { idxFirst++; }
  while ( ( idxLast >= idxFirst) && isspace( strSource[idxLast]))
  { idxLast--; }
  if ( idxLast >= idxFirst)
  {
    std::string strTrimmed = strSource.substr( idxFirst,
idxLast + 1 -
 idxFirst);
    return strTrimmed;
  }
  else
  {
    // this string contains only spaces
    return std::string();
  }
}

void test_functions_array()
{
  typedef function_base< const char *, std::string>
StringTransformer;
  typedef std::deque< StringTransformer*>
StringTransformersArray;
  typedef std::deque< std::string> StringsArray;
  StringTransformersArray aTransformers;
  StringsArray aDescriptions;
  aTransformers.push_back( functor_elem( surround_string('[', ']')
));
  aDescriptions.push_back( "Surrounding string with []");
  aTransformers.push_back( functor_elem( surround_string('{', '}')
));
  aDescriptions.push_back( "Surrounding string with {}");
  aTransformers.push_back( functor_elem( surround_string('<',
'>') ));
  aDescriptions.push_back( "Surrounding string with
<>");
  aTransformers.push_back(
    convert_functor_elem< const char *, std::string>(
truncate_string( 10) ));
  aDescriptions.push_back( "Truncate string to 10 chars");
  aTransformers.push_back(
    convert_functor_elem< const char *, std::string>(
truncate_string( 15) ));
  aDescriptions.push_back( "Truncate string to 15 chars");
  aTransformers.push_back( function_elem( first_half));
  aDescriptions.push_back( "Returning first half of
string");
  aTransformers.push_back( function_elem( second_half));
  aDescriptions.push_back( "Returning second half of
string");
  aTransformers.push_back(
    convert_function_elem< const char *,
std::string>( trim));
  aDescriptions.push_back( "Trims leading and trailing
spaces");

  const char * aTestStrings[] =
  {
    " First string to test. ",
    " Second string, that is.",
    "A more complicated string, a little bigger than
the rest",
    "Ok.",
    "  Last string. End.  ",
    NULL
  };
  const char ** pstrTest = aTestStrings;
  while ( pstrTest[ 0] != NULL)
  {
    StringTransformersArray::const_iterator
      itFirst = aTransformers.begin(),
      itLast = aTransformers.end();
    StringsArray::const_iterator itDescription =
aDescriptions.begin();
    const char * strSource = pstrTest[ 0];
    std::cout << "Original string: '"
<< strSource << "'" << std::endl <<
 std::endl;
    while ( itFirst != itLast)
    {
      std::cout
        << "Transformation:
" << *itDescription << std::endl;
      std::cout
        << "Transformed
string: '"
        << ( **itFirst)(
strSource) << "'" << std::endl << std::endl;
      ++itFirst;
      ++itDescription;
    }
    std::cout << "----------------"
<< std::endl << std::endl;
    pstrTest++;
  };
}

int main(int argc, char* argv[])
{
  test_functions_array();
  return 0;
}

以下是说明如何在数组中插入元素:

1.functor_elem( adapter_function):从适配函数生成一个算符封装。

2.convert_functor_elem( adapter_function):生成一个包含适配函数的算符封装
,这一函数包含一个变量并返回一个值。

3.function_elem( function):从相应函数生成一个算符封装。

4.convert_function_elem( function):从相应函数生成一个算符封装,与
convert_functor_elem相类似。




注意,在你的数组中,你必须把指针指向一个基类(function_base< Type,
ReturnType>)。所以,它们会生动通过”new”来生成。你必须在结束时删除这一
指针。我们建议你你采用一个指针变量,这样可以很容易地删除掉。

下面是把函数/算符集中在一个数组中的代码示例。



template<class Type, class ReturnType = void>
class function_base
{
public:
  virtual ~function_base() {}
  virtual ReturnType execute( Type) = 0;
  ReturnType operator()( Type value) { return execute( value); }
};

template<
    class Functor,
    class Type = typename Functor::argument_type,
    class ReturnType = typename Functor::result_type >
  class functor_wrapper_t
    : public function_base< Type, ReturnType>
{
public:
  functor_wrapper_t( Functor func)
    : m_func( func) {}
  ReturnType execute( Type value) { return m_func( value); }
private:
  Functor m_func;
};

// TypeTo, ReturnTypeFrom - the types we're converting to/from;
//
// for instance, the function prototype might not be exactly
// 'ReturnType function( const Type &)', but rather have another
// type as argument - one type that 'Type' can be converted to, and
// return a type that can be converted to 'ReturnType'
template< class Type, class ReturnType, class TypeTo = Type, class
ReturnFrom =
 ReturnType>
  class function_wrapper_t
    : public function_base< Type, ReturnType>
{
  typedef ReturnFrom (* function_type)( TypeTo);
public:
  function_wrapper_t( function_type func)
    : m_func( func) {}
  ReturnType execute( Type value) { return ( ReturnType)m_func( (
 TypeTo)value); }
private:
  function_type m_func;
};


template< class Functor>
  functor_wrapper_t< Functor> * functor_elem( Functor func)
{ return new functor_wrapper_t< Functor>( func); }

template< class Type, class ReturnType, class Functor>
  functor_wrapper_t< Functor, Type, ReturnType> *
convert_functor_elem( Functor
 func)
{ return new functor_wrapper_t< Functor, Type, ReturnType>( func); }

template< class Type, class ReturnType>
  function_wrapper_t< Type, ReturnType> *
    function_elem( ReturnType (* function)( Type))
{ return new function_wrapper_t< Type, ReturnType>( function); }

template< class Type, class ReturnType, class TypeTo, class
ReturnTypeFrom>
  function_wrapper_t< Type, ReturnType, TypeTo, ReturnTypeFrom>
*
    convert_function_elem( ReturnTypeFrom (* function)(
TypeTo))
{ return new function_wrapper_t< Type, ReturnType, TypeTo,
ReturnTypeFrom>(
 function); }
--
         那一年,我生命中吹过的风,在这里轻轻地转了一个弯... ...

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.44.81]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店