
On Jul 20, 2008, at 9:21 AM, Zeljko Vrba wrote:
And the basic question remains unanswered for me: How does MPL (or fusion for that matter) help in making more maintainable code? More maintainable as in:
- less lines of code - code that is easier to understand - code that is easier to inspect at runtime with a debugger - code that can be modified by a C++ developer who does not know every dark corner of the template language - code that is written faster (i.e. takes less time to get a successful compilation) and works correctly the first time it is written
How are fusion/MPL useful to an *application* programmer, not a library developer?
I'm not really into the whole MPL scene myself, but I'll give you examples where I used it. A while ago, Boost.Test added support for automatic unit tests. I tried them out, and converted Boost.Rational to use them. The test come in the form of a function you write with a special macro. A similar macro was provided that made a function template instead, and you supply a list of types to apply on that template for testing. The list is in the form of a MPL list: typedef boost::mpl::list<short, int, long, MyInt> rational_testing_list; And I could apply the same tests for different versions of boost::rational<T>. Recently, I redid the integer-selection class templates to use Boost.Test. Before this (like in Boost 1.35) that test (integer_test.cpp) used a LOT of macros that assumed 32-bit values. I wanted something more maintainable by the compiler proper. (For instance, someone extended a macro for 64-bit support, although I never supported that for any other code.) I decided to go with automatic test templates and lists. The base list was like: typelist boost::mpl::vector<unsigned char, unsigned short, unsigned, unsigned long, unsigned long long> unsigned_integer_list; with some alterations: 1. Use "__int64" instead of "long long" on Windows systems 2. Exclude both if I'm not on a 64-bit system 3. Exclude types that are strong-typedefs of a "smaller" type (so "unsigned char" is the only type guaranteed) done by the preprocessor. I use MPL to synthesize the data I actually needed for the tests from this list. 1. Create a list of corresponding signed types (help from Boost.TypeTraits) 2. Create a list of bit lengths used for each integral type, using a custom meta-function I made with std::numeric_limits. This means that I didn't not hard-code the {8, 16, 32, 64} values and the tests will work on platforms without a 64-bit type, or even on old systems that don't use the 8/16/32 system (like 36-bit ints with 9- bit char). 3. A list of all the median bit lengths between the values in [2], so I can test lengths between the exact ones. 4. A combined list of [2] and [3] 5. [4] extended with a length beyond all valid bit lengths In addition, I changed the implementation of the integer-selection classes. Before they could give a compiler error if a given input length was invalid. Now they're MPL-compatible and just lack a member "type" if the input is invalid. (The old templates now call these new ones and still cause a hard error.) Without this, tests using [5] aren't possible. Said tests use SFINAE to make decisions. (I think that MPL lists are limited to 20 elements total. So I made list [3] to be selective. Otherwise, I could have carpet-bombed with range_c<int, 0, 65> or such.) All of these lists are compile-time, but based on a list I couldn't hard-code. It would have been harder without MPL manipulations. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com