Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What comes first - template instantiation vs. macro expansion?

Let's consider a code example like this (it is just an artificial example to combine define and template, don't look for any sense it it):

#define COMMA ,

template <typename A> class Test
{
public:
    Test(){}

    void Foo(A var COMMA int test);
};

Test<int> Knarz;

Question:

Is my assumption correct that, first the preprocessor will search/replace all occurrences of COMMA and second the compiler will instantiate any templates in that order?

Followup:

If the above answer is 'yes', as I hope it to be, can you explain why this solution using templates and defines works?

like image 341
Ronald McBean Avatar asked Apr 18 '12 11:04

Ronald McBean


3 Answers

The preprocessor is run before the compiling itself is done, so your assumption that the preprocessor will replace COMMA before the template is instantiated is correct.

For your followup: The solution has little to do with templates. The problem there is that the preprocessor will take commas inside the braces to be argument separators for the macro, since it doesn't parse the C++ code to see that it is the separator for the template arguments. So the COMMA macro is used to insert the , for separating template arguments only after the MOCK_CONSTANT_METHOD0 has been substituted. I am however not sure if this is guaranteed to work, since I don't know the guarantees for the order of macro-substitution by memory. If COMMA would be substituted before MOCK_CONSTANT_METHOD0 everything falls apart and the code once again doesn't compile.

Edit: After looking into the standard I think the solution should generally work, since the preprocessor will find MOCK_CONSTANT_METHOD0 first and replace it. Only then will it examine the result of the replacement to find the COMMA macro. No guarantees though.

like image 148
Grizzly Avatar answered Oct 20 '22 00:10

Grizzly


First macros and template after, actually macros will just apply the changes on the existing code before the compilation. So in this solution the comma will generate a template code like:

MOCK_CONSTANT_METHOD0(aMethod, const QMap<QString,QString>());

before the compilation.

So for the second question:

It is related with how the gmock framework works actually the MOCK_CONSTANT_METHOD0 is a macro so the line will be transformed to something else. Markus Mayr said that comma will be translated as a parameter separator so it is related with a how the gmock macros will be transformed in this case I guess that first the mock macro will be replaced and after the comma will be applied internally and this is the reason why it does work with a macro and not just with a comma.

like image 29
AlexTheo Avatar answered Oct 20 '22 00:10

AlexTheo


The preprocessor is first.

I think the referenced solution is a pretty bad idea as it depends on the order by which the preprocessor performs its substitutions. Since the whole charade is only used to prevent the preprocessor from choking on the comma in the template argument list, it would be much better to use a typedef.

like image 26
Michael Wild Avatar answered Oct 19 '22 23:10

Michael Wild