开发者

Writing a function using a macro with variable number of arguments

How do you write a macro with variable number of arguments to define a function? Suppose that we define the class class1 with 2 parameters and class class2 with three parameters.

class class1 {
public:
   int arg1;
   int arg2;
   class1(int x1, int x2): arg1(x1), arg2(x开发者_如何学JAVA2) {}
};
class class2 {
public:
   int arg1;
   int arg2;
   int arg3;
   class1(int x1, int x2, int x3): arg1(x1), arg2(x2), arg3(x3) {}
};

For each class that I define or even classes that have been defined before I want to write the following:

template<> inline void writeInfo<class1>(const class1& obj, FILE* fp) {
    writeAmount(2, fp);
    writeName("arg1", fp);
    writeInfo(obj.arg1, fp);
    writeName("arg2", fp);
    writeInfo(obj.arg2, fp);
}
template<> inline void writeInfo<class2>(const class2& obj, FILE* fp) {
    writeAmount(3, fp);
    writeName("arg1", fp);
    writeInfo(obj.arg1, fp);
    writeName("arg2", fp);
    writeInfo(obj.arg2, fp);
    writeName("arg3", fp);
    writeInfo(obj.arg3, fp);
}

We do not need to care about the definitions of writeAmount, writeName or writeInfo. What I would like to do is write something like:

MACROWRITEINFO(class1, 2, arg1, arg2);
MACROWRITEINFO(class2, 3, arg1, arg2, arg3);

Is it possible to create such macro so that it can expand to the above template definitions? I've read in a lot of places that macros are evil, but in this case I believe that they are very helpful since they'll reduce the amount of code I type and thus the amount of typos I'll make during the creation of the template functions.


First of all you should improve your formatting/code. Your code lacks "class" keywords and semicolons after classes definitions - when you post a snippet make sure it's proper code, because some people (i.e. me) will try to compile it.

Second of all, dont use function template specialization. If macros are evil, then they must be satan incarnation. Just stick to the good old overloads. See here for details.

And at least - an answer. You could mess around with variadic macros if all args were of the same type - for example, you could create an array inside writeInfo function and iterate over elements. Since it's cleary not the case here you can define many variants of MACROWRITEINFO macro for different number of parameteres, using some common blocks to reduce code repetition. For example:

#define MACROWRITEINFO_BEGIN(type, amount)  \
void writeInfo(const type& obj, FILE* fp)   \
{                                           \
    writeAmount(amount, fp);

#define MACROWRITEINFO_NAMEINFO(name)       \
    writeName(#name, fp);                   \
    writeInfo(obj.##name, fp);

#define MACROWRITEINFO_END()                \
}

Using those you can now define variants based on number of arguments.

#define MACROWRITEINFO1(type, arg1) \
    MACROWRITEINFO_BEGIN(type, 1)   \
    MACROWRITEINFO_NAMEINFO(arg1)   \
    MACROWRITEINFO_END()

#define MACROWRITEINFO2(type, arg1, arg2) \
    MACROWRITEINFO_BEGIN(type, 2)   \
    MACROWRITEINFO_NAMEINFO(arg1)   \
    MACROWRITEINFO_NAMEINFO(arg2)   \
    MACROWRITEINFO_END()

And so on...

EDIT: Well I guess it is possible to use variadic macros here. Take at look at this SO question. It's pure madness, but you should be able to achieve what you want.

EDIT: My idea was to expand variadic arguments into array then iterate over them; if they were of the same type, let's say int, you could write:

#define VAARGSSAMPLE(...) \
    int args[] = { __VA_ARGS__ }; \
    for (int i = 0; i < sizeof(args)/sizeof(int); ++i) \
    { \
        printf("%d\n", args[i]); \
    }

VAARGSSAMPLE(1, 5, 666);

So if all your variables were of the same type you could put them in an array. But they are not, so it won't do. If you really, really want to stick to variadic arguments go to my first edit.


I don't think it's possible to do that with a macro. You can use variable arguments (variadic) but you can't generate code which depends on the arguments.

I'd suggest you create a DSL (e.g. simple xml..) and generate code out of it. this is much cleaner and good practice.

You could do this:

<writeInfos>
    <writeInfo class="class1" amount="3">
        <arguments>
            <argument>arg1</argument>
            <argument>arg2</argument>
        </arguments>
    </writeInfo>
</writeInfos>

Then create source code out of this. You should add this step in your build process..

But you can also define something much simpler.. you could put your MACROWRITEINFO "functions" in a text file and parse it yourself..

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜