1.4.2. Formatter

Another frequent programming task is generating information for the user. Often you have to assemble a string from several parts. Most of the time there is some sort of format string to determine the basic information with some placeholders at the desired position which are substituted with actual values.

A lot of people are using the printf() family for outputting. Unfortunately these are not typesafe. And nor are they appropriate for translations when the positions of the substituted parameters are swapped for grammatical reasons.

So I decided to implement a typesafe approach which also takes the position of the substituted values into account: each inserted value is converted into its string representation and substitutes the placeholder with the lowest number. Since such a placeholder consists of a percent sign and a single digit there are up to ten substitutions possible.

The built-in methods handle the common data types like int, float or std::string. But it is also easily possible to extend the output capabilities for your own data types. No changes inside the mockpp framework are needed, it needn't even be in the mockpp namespace.

In the case you don't really want to output the content of an object but simply need operator<<() because mockpp insists on it for it's built-in debugging output you may use the default templates instead. To avoid pontential conflicts these templates must be enabled by setting the macro MOCKPP_ENABLE_DEFAULT_FORMATTER before including the first mockpp header file.

It is also possible to reuse already existing streaming operators for std::basic_ostream. The macros MOCKPP_OSTREAMABLE and MOCKPP_OWSTREAMABLE create code for mockpp which uses the standard streaming functions.

This collection of functions is inspired by the QString class which is part of the Qt™ framework by Trolltech.


  class Person 1
  {
    public:

      Person(std::string in_name, unsigned in_age)
        : name(in_name)
        , age(n_age)
      {}

      String toString() const
      {
        String ret;
        ret << name << "(" << age << ")";
        return ret;
      }

    private:

      std::string  name;
      unsigned     age;
  };

  String & operator<< (String &formatter, const Person &pers)
  {
     formatter << pers.toString(); 2
     return formatter;
  }

  class AnotherPerson : public Person
  {
  // ..
  };

  std::ostream & operator<< (std::ostream &os, const AnotherPerson &pers)
  {
     os << pers.toString();
     return os;
  }

  MOCKPP_OSTREAMABLE(AnotherPerson) 3

  Person pers("Bob", 6);
  AnotherPerson otherpers("Alice", 7);
  String  format = "%5 and %4 say: %3 plus %2 gives %1";
  format << "three" << "two" << "one" << pers << otherpers;
  std::cout << format << std::endl;

1

Create a user defined data type with some internal data elements. Implement a method to create a string representation of the internal variables.

2

Output the string representation of the object.

The resulting output: Alice(7) and Bob(6) say: one plus two gives three

3

Output the string using an existing standard streaming operator.