Boost logo

Boost :

From: Martin Fuchs (martin-fuchs_at_[hidden])
Date: 2002-05-13 06:25:44


Some time ago I had a similar idea about string formating using C++.
I think it's even more flexible. What about this aproach:

cout << fmtstring("This is %1 %2 %3") + "a" + "simple" + "example" << "\n";

Default formating outputs just strings instead of the numbered placeholders.

To change the order of arguments, you just have to alter the format string:

cout << fmtstring("This is %1 %3, to be treaten as %2")
                          + "a" + "simple" + "example" << "\n";

To implement this, fmtstring would at first just collect all the arguments,
and build the resulting string on demand. This means, at the time, some one
asks for the result calling function str() or operator const char*(). Just
in case the string is used more than one time, the result can be buffered
internally in fmtstring.

If you want to, you can also use the printf-like formats:

string s = fmtstring("This is %1%3s %2%s %3-20s")
                            + "a" + "simple" + "example";

Why use only numbered arguments?
By using just strings as names, one can do somethiong like this:

string result = fmtstring("name: %name%s age: %age%d") +
                            fmtargument("name") * "billy" +
                            fmtargument("age") * 18;

This has the benefit of more readable format strings. And we could design
something like an recordset-class. This would contain values for a list of
argument names, and it can be taken as the source for formating a string. I
think an example might be a bit more clear: ;-)

recordset data;

data * "name" = "billy";
data * "age" = 18; /* of course this means, we have to store not
only strings, but also numbers */

string result = fmtstring("name: %name%s age: %age%d") + data;

The recordset class could be implemented in a way like this:

template<typename variant_type>
    struct recordset : public list<variant_type>
{

   ...

    variant_type& assign(const string& name, const T& value);

    naming_type& operator *(const string& name)
        {return naming_type(name);}

    struct naming_type {
        naming_type(recordset& owner) : _owner(owner) {}

        recordset& _owner;

        ...

        assignment_type& operator*(const string& name)
           {return assignment_type(_owner, name);}
    };

    struct assignment_type {
        assignment_type(recordset& owner, const string& name)
         : _owner(owner), _name(name) {}

        recordset& _owner;
        const string& _name;

        ...

        template<typename T> variant_type& operator=(const T& value)
           {return _owner.assign(_name, value);}
    };
};

Mhh - am I getting a bit off topic? :-)

Greets,

Martin Fuchs


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk