
I've just finished reading C++ Template Metaprogramming again. I just don't get it.
Why would someone use a type container?
I have used enable_if, along with some of the logic functions for managing an overload set. Otherwise, I'm clueless.
I'd really like a reference to an MPL primer or some case studies.
The book contains a case study in which type sequences are used to describe the rows of a state machine's transition table. Was that not a sufficient motivating case?
FSMs are not something I'm familiar with. I didn't really notice the vector of rows until recently. How is the FSM approach in your book better than arrays of structs? I didn't see any advantage, and the supporting code is too complex. There must be an advantage, otherwise, why would you work so hard to write these things? I'll try to implement a reusable FSM framework, without MPL. Then, perhaps, advantages/disadvantages of MPL would be more apparent to me. Is there a good way to post hundreds of SLOCs for discussion? I don't have a website. BTW, on the boost website, there are three versions of the FSM player example. A ReadMe.txt to explain the differences would be helpful.
Too much pain with very little gain.
What, specifically, do you find painful?
Well, you asked... I write stuff that I think should work, but the compiler issues tons of error messages. Pitfalls like when to use typename. Brain cramps trying to comprehend the compile-time/run-time boundary. Recently, I tried to avoid using a large 150-case switch statement using metaprogramming. Each MessageNN has a unique static const int TAG member. They all derive from a common Message base class that has the common message header, including the tag. The only thing each case did was something like. switch (msg.tag()) { case Message26::TAG: cout << static_cast<const Message26&>(msg) << endl; break; case Message27::TAG: cout << static_cast<const Message27&>(msg) << endl; break; ... } That is, upcast a received message (over a wire) and print it. Virtual functions cannot be used because the message can have no vtbl. I eventually just did the big switch like I have for twenty years. The pain (frustration) comes from believing there's a "better" way, but not knowing how to realize it. Pain, too, because without a mentor to guide me, I feel like I'm walking around trying to drive in screws with my shiny new hammer. Painful because after you get a nifty mpl::vector of MessageTypes, you realize after the 50th message, that it won't scale up to 150. Painful because compile times take much longer. (VC8 takes a lot longer, not sure why). Painful because I don't understand the runtime and memory trade-offs anymore. i.e. painful because it makes me realize how stupid I still am, in spite of all my past successes. Printf and void* have served me well.
Time to ask for help. Rereading this, it sounds negative. Really, I think the MPL is really cool!
Cool, how can we help?
Do know how to do a mind-meld? (Spock recoiled, his face white with shock. He had never experienced such chaos before.) I need to be patient and ask one question at a time. There is a lot of really difficult material packed into a deceptively slim book. So, back to that switch statement... is there a better way? I thought of using something like: template <Tag> struct DerefTag { typedef Message type; } And then specializing it like this. template <> struct DerefTag<Message26::TAG> { typedef Message26 type; } But that can only be used with compile-time constants, limiting its usefulness. Now I can write each case statement like this: case Message26::TAG: cout << static_cast<const DerefTag<Message26::TAG>::type&>(msg) << endl; break; That's not better, its worse. Sigh. Should I give up? Is there a better way? BTW, how do compilers handle big switches? How do they find the matching case? Would an stl::map or sorted stl::vector of callback functors yield better portable performance? Hmmm... (<--- the sound I make before wasting even more time). terry