# Interesting use of #include

This topic is 4646 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi, Check out this coding tip I found on kamron.net:
Quote:
Anyways... I like this kind of thing, but what do you guys think about it? I think, if I tried to pull something like this at an actual company, people might think this is a really "hacky" way of doing things. (I've noticed a lot of coders in general seem to be extremely wary of preprocessor tricks) Thanks, roos

##### Share on other sites
This is similar to things I have done in the past. It's basically a roundabout way of trying to support lambdas in C++. The problem is, preprocessor tricks like this tend to be very difficult to read and to debug, since they generate a lot of text that doesn't have a good line number. I'm not saying don't use it; just don't use it if you can possibly think of a better way.

##### Share on other sites
Quote:
 Original post by Snefteldon't use it if you can possibly think of a better way.

I could think of one but I am sure it would get all of the C++ fanatics enraged.

##### Share on other sites
I think its a sloppy way of programming and makes it hard to see what is going on. In this case, I would make a function that returns a pointer to an animal and takes in the byteread. Just encapsulate the switch in the function and return the pointer. Something like this:

Animal* CreateAnimal(int byteread){    switch(byteread)    {    case: ENUM_CAT:        {            return new CAT();            break;        }    ...    }}

This doesn't solve the problem when you have to do different things though, but that should be a copy and paste. In general, if you design ahead of time, you won't run into the problem of needing to add a class that you may have forgotten. It is times like that when I wish C++ had first class functions, like Scheme does.

##### Share on other sites
Quote:
Original post by The Reindeer Effect
Quote:
 Original post by Snefteldon't use it if you can possibly think of a better way.

I could think of one but I am sure it would get all of the C++ fanatics enraged.

I wanna hear it [smile] pm it to me... unless it involves a language other than C++, in which case I might get enraged [smile]

##### Share on other sites
I'd be interested in it too. Just post it in here. I promise I won't become enraged.

##### Share on other sites
It's not a particularly elegant solution, but it works - and I wouldn't be opposed to it for over-the-network stuff. I'd wrap it all up in a nice API though. Here's what I'd probably use off first bat for a network syncronization:

typedef animal (*animal_factory_function_t)( void );template < typename base_type , typename implementation_type >base_type * factory( void ) {    return new implementation_type;}animal_factory_function_t animal_factory[] =    { & factory< animal , cow >    , & factory< animal , horse >    , & factory< animal , cat >    , & factory< animal , crow >    , & factory< animal , sheep >    };assert( (byteread >= 0) && (byteread < size_of( animal_factory )) );//note: NOT the operator sizeof, rather industry::size_of, which will return the number of elements for both containers and C-style arrays.animal * animal = animal_factory[ byteread ]();
(untested)

Although I'd probably wrap *_factory[] into a class with an API as follows:

Which would of course have the error checking and the like. This would then allow me to easly switch to the ENUMs method if I found the compiler could create better code with it. Macros could be used to shorten each line, or you could play around with classes, static functions and typedefs.

If one is doing a load/save style operation, I'd use Boost.Serialization.

Edit: Bloody hell, go in there you assert and related comments!!! Go go go!!! My internet is such ****....

##### Share on other sites
Nice MM, my thoughts exactly.
switch statements are an unnecesary evil.

[razz]Lookup table pwns switch in 99% of cases.[razz]

##### Share on other sites
Cool, yeah that makes sense Sneftel... only save something like this for when it's really needed. Also it'd probably have to be made part of the company's coding guidelines because if everyone else is handling say, serialization one way, and you're making up crazy stuff on your own, you gonna get fired :) (even if your way is better!)

I like your idea MaulingMonkey, that'd definitely work although it does take a bit of work to figure out what it's doing for the person who's maintaining the code...

Thanks also for the link to the boost serialization stuff... I'm definitely curious about that. At my previous company, the I/O code was extremely tedious. To save or load a file, every parameter had to be separately fread'd or fwrite'd... Which isn't all that horrible by itself, but we had one of those functions for every version of every file format all the way down to 1.0 (this is of course so the world editor won't choke if you give it an old file or something like that).

So, I made a crazy system to solve this which would let you define a file format by an array of ID's which describe its structure, which allowed you to easily create new file formats as an extension of the old one, e.g.:

PARAM_ID MagicSpell_100[] ={    PARAM_HEADER1,          // parameters- can represent a variable, a structure,    PARAM_ATTACK_DAMAGE1,   // or a cluster of different related things    PARAM_MP_USAGE1,    };// create a new format which has everything the v100 did, plus 1PARAM_ID MagicSpell_101[] ={    COPY_STRUCTURE( MagicSpell_100 ),    PARAM_SOME_EXTRA_PARAMETER1};

The loading function would step through all these parameters, do a switch on the PARAM_ID, and do read/write accordingly. At the time I was pretty happy with this system because it hugely reduced the amount of code that had to be duplicated and made I/O a lot more organized. But this is probably even worse than that tip about #includes in terms of preprocessor abuse and unmaintainable code, plus it only really has a benefit for files which are likely to go through more than 2-3 versions..

roos

##### Share on other sites
You should have a look at the Boost Preprocessor library. They use that kind of things extensively to pull off some really cool tricks.

##### Share on other sites
Quote:
 Original post by iMalcNice MM, my thoughts exactly.switch statements are an unnecesary evil.[razz]Lookup table pwns switch in 99% of cases.[razz]

In this case, it wouldn't help unless you had the table referencing functions which returned the new animal, so unless you wanted to create a new function for every animal, you'd stick to the switch statement.

I personally like the way they used the include file to generate those things (even if it is a little harder to follow).