Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlb_transformiterator
[Package bdlb]

Provide a wrapping iterator that invokes a functor on dereference. More...

Namespaces

namespace  bdlb

Detailed Description

Outline
Purpose:
Provide a wrapping iterator that invokes a functor on dereference.
Classes:
bdlb::TransformIterator functor-invoking iterator wrapper
bdlb::TransformIteratorUtil utility for creating transform iterators
Description:
This component implements a class template, bdlb::TransformIterator, that stores an underlying iterator and a one-argument functor. Iterator operations are passed through to the underlying iterator, with the exception of dereference. For dereference, the functor is invoked on the result of dereferencing the underlying iterator, and the result of the functor invocation is returned. This component also implements a utility class, bdlb::TransformIteratorUtil, that provides a function template for creating TransformIterator objects.
The templates expect two parameters. The first parameter, designated FUNCTOR, is the type of a callable object that can be invoked with a single argument. When compiling with C++03, this type must be either a function pointer or otherwise have a type from which bslmf::ResultType can determine the result type of invoking the functor (see bslmf_resulttype). The second parameter, designated ITERATOR, is the type of an object that models an iterator from which values may be obtained, i.e., a type such that bsl::iterator_traits<ITERATOR> exists and for which typename bsl::iterator_traits<ITERATOR>iterator_category derives from bsl::input_iterator_tag (see bslstl_iterator). Note that object pointer types qualify.
Note that bdlb::TransformIterator is more useful in C++11 or later than in C++03, because lambdas can be used as function objects to match a FUNCTOR of type bsl::function<RETURN_TYPE(INPUT_TYPE)>.
Usage:
This section illustrates intended use of this component.
Example 1: Totaling a Grocery List:
Suppose we have a shopping list of products and we want to compute how much it will cost to buy selected items. We can use bdlb::TransformIterator to do the computation, looking up the price of each item.
First, we set up the price list:
  bsl::map<bsl::string, double> prices;
  prices["pudding"] = 1.25;
  prices["apple"] = 0.33;
  prices["milk"] = 2.50;
Then, we set up our shopping list:
  bsl::list<bsl::string> list;
  list.push_back("milk");
  list.push_back("milk");
  list.push_back("pudding");
Next, we create a functor that will return a price given a product. The following rather prolix functor at namespace scope is necessary for C++03:
  #ifndef BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE
  class Pricer {
    private:
      // DATA
      const bsl::map<bsl::string, double> *d_prices_p;  // price list

    public:
      // PUBLIC TYPES
      typedef double result_type;

      // CREATORS
      explicit Pricer(const bsl::map<bsl::string, double> *prices);
          // Create a 'Pricer' object using the specified 'prices'.  The
          // lifetime of 'prices' must be at least as long as this object.

      // ACCESSORS
      double operator()(const bsl::string& product) const;
          // Return the price of the specified 'product'.
  };

  // CREATORS
  Pricer::Pricer(const bsl::map<bsl::string, double> *prices)
  : d_prices_p(prices)
  {
  }

  double Pricer::operator()(const bsl::string& product) const
  {
      bsl::map<bsl::string, double>::const_iterator i =
                                                   d_prices_p->find(product);
      return i == d_prices_p->end() ? 0.0 : i->second;
  }
  #endif
Then, we create the functor object. In C++11 or later, the explicit functor class above is unnecessary since we can use a lambda:
  #ifndef BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE
  Pricer pricer(&prices);
  #else
  auto pricer = [&](const bsl::string &product) { return prices[product]; };
  #endif
Now, we need a pair of transform iterators to process our grocery list. We can use TransformIteratorUtil::make to create those iterators, avoiding the need to explicitly name types. We create the iterators and process the list in one step, as follows:
  double total = bsl::accumulate(
      bdlb::TransformIteratorUtil::make(list.begin(), pricer),
      bdlb::TransformIteratorUtil::make(list.end(), pricer),
      0.0);
Finally, we verify that we have the correct total:
  assert(6.25 == total);
Example 2: Totaling the Grocery List Again:
In the previous example, we did not explicitly name our iterator type. We may want to do so, however, if we intend to reuse iterators, or store them in data structures. We will rework the previous example using explicitly typed iterators. We also demonstrate how a single iterator type can deal with multiple functors.
First, we notice that we have two different functor types depending on whether we compile as C++03 or C++11. To abstract away the difference, we will use a bsl::function functor type that is conformable to both: Then, we create a pair of these iterators to traverse our list:
  Iterator groceryBegin(list.begin(), pricer);
  Iterator groceryEnd(list.end(), pricer);
Now, we add up the prices of our groceries:
  double retotal = bsl::accumulate(groceryBegin, groceryEnd, 0.0);
Finally, we verify that we have the correct total:
  assert(6.25 == retotal);
Example 3: Summing Absolute Values:
Suppose we have a sequence of numbers and we would like to sum their absolute values. We can use bdlb::TransformIterator for this purpose.
First, we set up the numbers:
  int data[5] = { 1, -1, 2, -2, 3 };
Then, we need a functor that will return the absolute value of a number. Rather than write a functor object, we can use a simple pointer to function as a functor:
  int (*abs)(int) = &bsl::abs;
Next, we create the transform iterators that will convert a number to its absolute value. We need iterators for both the beginning and end of the sequence: Now, we compute the sum of the absolute values of the numbers:
  int sum = bsl::accumulate(dataBegin, dataEnd, 0);
Finally, we verify that we have computed the sum correctly:
  assert(9 == sum);