16

I am trying to use macro for calling appropriate object based on the type.

#define DELEGATE_FUNC(FuncName, kind, paramPtr)         \
    if (kind == 1) {                                    \
        return PolicyObject1.##FuncName(paramPtr);      \
    }                                                   \
    else {                                              \
        return PolicyObject2.##FuncName(paramPtr);      \
    }                                                   \
    return 0;                                           \

(PolicyObject1 & PolicyObject2 are two static objects.) Now when using the macro, e.g.

DELEGATE_FUNC(ProcessPreCreate, 1, null_ptr);

It compiles fine in VS 2015, but gives error with LLVM "Pasting formed an invalid processing token '.ProcessPreCreate'"

I looked for, and found a few posts and understood it up to some level - Need double level of indirection, e.g. Why do I need double layer of indirection for macros?

However I am unable to define those two layers of macro, can anyone help?

(Please leave aside the discussion on design aspects)

Thanks

Nitesh
  • 2,681
  • 4
  • 27
  • 45
  • 1
    What do you want the macro to expand to? It doesn't make sense to paste a period and an identifier together. – aschepler Sep 22 '17 at 03:12
  • And I bet the error says "an invalid", not "and invalid". – aschepler Sep 22 '17 at 03:14
  • Just want to exapnd to PolicyObject1.ProcessPreCreate(paramPtr) or PolicyObject2.ProcessPreCreate(paramPtr) based on kind. – Nitesh Sep 22 '17 at 03:14
  • 4
    Can't you use PolicyObject1.FuncName instead of PolicyObject1.##FuncName? That is just straight macro substitution: nothing fancy. Alternatively, why not use templates. - They are a lot easier to debug. – cup Sep 22 '17 at 03:14
  • I want to use DELEGATE_FUNC for different functions, say DELEGATE_FUNC(ProcessPreCreate, 1, null_ptr); DELEGATE_FUNC(ProcessPostCreate, 1, null_ptr); and lot more – Nitesh Sep 22 '17 at 03:17
  • 1
    C and C++ are different languages. Choose *one*. – John Bollinger Sep 22 '17 at 03:21
  • Sure, you can use it for different functions. You don't need token-pasting. You're trying to make `.ProcessPreCreate` a single token. It isn't. Drop the `##`s from your macro definition and let it treat `.` followed by `ProcessPreCreate` (or `.` followed by `ProcessPostCreate`) as two separate tokens. (More briefly, Daniel H's answer is correct.) – Keith Thompson Sep 22 '17 at 03:33
  • @JohnBollinger Can you elaborate? How does that comment help? Especially as I requested to ignore design aspect. – Nitesh Sep 22 '17 at 03:33
  • 1
    @Nitesh: C and C++ rules are subtly different in some ways. I don't think those differences affect your question, but I can't be 100% sure of that. Presumably you're using either a C compiler or a C++ compiler to compile your code. That determines whether your question should be tagged `c` or `c++`. – Keith Thompson Sep 22 '17 at 03:35
  • Yes @KeithThompson, Thats the way. Thanks – Nitesh Sep 22 '17 at 03:35
  • Yes C & C++ are different languages, but a lot is common and I consider macro to be one of them that's why I tagged both. – Nitesh Sep 22 '17 at 03:37
  • Ok, So I removed C tag, as the question, though about macro expansion, was mainly related with '.' operator and calling functions on objects. – Nitesh Sep 22 '17 at 03:38
  • 1
    @Nitesh: "*but a lot is common and I consider macro to be one of them*" -- Just for future reference, the C standard specifies the preprocessor in section 6.10, and the C++ standard specifies its preprocessor in section 16. Have you compared those specifications and confirmed that they're compatible? Quite possibly they are, but by limiting your question to one language or the other you reduce the number of things you and people trying to help you need to worry about. – Keith Thompson Sep 22 '17 at 15:36
  • Got it, so already removed C tag. – Nitesh Sep 23 '17 at 14:15

2 Answers2

40

When the compiler reads your C++ file, one of the first steps is dividing it into tokens like identifier, string literal, number, punctuation, etc. The C preprocessor works on these tokens, not on text. The ## operator glues tokens together. So, for example, if you have

#define triple(foo) foo##3

Then triple(x) will get you the identifier x3, triple(12) will get you the integer 123, and triple(.) will get you the float .3.

However, what you have is .##FuncName, where FuncName is ProcessPreCreate. This creates the single token .ProcessPreCreate, which is not a valid C++ token. If you had typed PolicyObject1.ProcessPreCreate directly instead of through a macro, it would be tokenized into three tokens: PolicyObject1, ., and ProcessPreCreate. This is what your macro needs to produce in order to give valid C++ output.

To do that, simply get rid of the ##. It is unnecessary to glue the . to the FuncName, because they are separate tokens. To check this, you can put a space between a . and a member name; it will still compile just fine. Since they are separate tokens, they should not and cannot be glued together.

Daniel H
  • 7,223
  • 2
  • 26
  • 41
5

delete "##".

#define DELEGATE_FUNC(FuncName, kind, paramPtr)     \
if (kind == 1) {                                    \
    return PolicyObject1.FuncName(paramPtr);        \
}                                                   \
else {                                              \
    return PolicyObject2.FuncName(paramPtr);        \
}                                                   \
return 0;                                           \
Nitesh
  • 2,681
  • 4
  • 27
  • 45
shede333
  • 1,105
  • 10
  • 7