Click here to Skip to main content
15,889,527 members
Articles / Programming Languages / C++

Fluent Functors

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
22 May 2011CPOL1 min read 9.6K   2  
I've been learning about BOOST Spirit; a C++ expression based compiler generator. One of the examples is for a Roman Numeral parser. This contained the following interesting code for pre-loading a symbol table...

I've been learning about BOOST Spirit, a C++ expression based compiler generator. One of the examples is for a Roman Numeral parser. This contained the following interesting code for pre-loading a symbol table:

C++
struct ones_ : qi::symbols<char, unsigned>
{
    ones_()
    {
        add
            ("I"    , 1)
            ("II"   , 2)
            ("III"  , 3)
            ("IV"   , 4)
            ("V"    , 5)
            ("VI"   , 6)
            ("VII"  , 7)
            ("VIII" , 8)
            ("IX"   , 9)
        ;
    }

} ones;

So,

  • struct ones_ is a new class definition.
  • ones_() is the constructor.
  • The call to add("I", 1) is a call to the member function add associating the string "I" with the value 1 by adding them to the symbol table.

There's nothing particularly strange there. However, the continuation, i.e. add()()()()()... looked a little odd and puzzled me for a minute or so. Then I realized add() must be returning *this and the other ()s were invoking the parenthesis operator, i.e. in this case, ones_& operator()(const char*, const int);.

Following this little revelation, to confirm the theory, I constructed the following program which sums the numbers 1-6, printing 21.

C++
#include <iostream>

class Func
{
private:
    int m_sum;

public:
    Func(const int n) : m_sum(n) { /* Empty */ }

    const int Sum() const { return m_sum; }

    Func& operator()(const int n)
    {
 m_sum += n;

 return *this;
    }

    static Func add(int n) { return Func(n); }
};

int main()
{
    std::cout << Func::add(1)(2)(3)(4)(5)(6).Sum() << std::endl;
}

All that's needed is a seed function, in this case add() which returns *this followed by operator()(). It would work fine without the named seed function using just operator()() but then it would lose a little meaning.

This isn't really that helpful and in most circumstances probably constitutes obfuscated code. However, it's certainly cute and where overloading is done fully and with meaning of which Spirit is a case in point, then it becomes an effective and usable syntax.

As Fluent Programming seems to be on rise, this is another demonstration of it within C++, just like iostreams. The added Syntactical Sugar provided by C++'s Functor mechanism makes for Fluent Functors.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
United Kingdom United Kingdom
My day job is mostly working in C++ with a bit of C#. I write a fair amount of command line based tools and really wish they could have a GUI front-end to them hence why I spend my spare time working with WPF.

I started a blog few years back but didn't do a lot with it. I've started describing some of the interesting programming things I come across on it. Please take a look.

Comments and Discussions

 
-- There are no messages in this forum --