Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Fluent Functors

0.00/5 (No votes)
22 May 2011CPOL1 min read 9.8K  
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)