I am trying to execute the following code:
#define channel1 10
#define channel(id) channel##id
int main(){
int id = 1;
cout << channel(id)<<"\n";
return 0;
}
I get the following error:
error: use of undeclared identifier 'channelid'
Instead, I want an output to be 10, as channel(id)
should be preprocessed to channel1
and which replaces the value with 10.
Is there any way to achieve it?
The problem is caused because you're trying to mix information that it is considered at different stages in the processing of the code.
Macros and all CPP (C-Pre-Processor) stuff happens (as its own name indicates) before anything else. It doesn't know anything about the variable values (at most, about #define) and most of what it does is text wrangling.
Some of the variable values might be known at compile time (see
constexpr
) ... but most of them will only be known at run time.So, in summary your code fails because the preprocessor knows nothing about the
id
variable.Edit: Explaining the sum example.
We have this code
x.cpp
And this code compiles and works fine.
Let's look at what happens behind the scenes.
All C/C++ source files are preprocessed. This means that they are evaluated with a different language than either C or C++: the CPP (C-preprocessor). This CPP is the one responsible of all the #... stuff (for example searching and including the header files) and as I said, has nothing to do with C or C++.
In fact, you can even run it without the compiler (try
cpp x.cpp
) or you can instruct the compiler to only execute this phase (g++ -o x.i -E x.cpp
)If we look into x.i:
We can observe several things:
You need another layer of indirection and for
id
to be a macro, not a variable (it can't work with a variable -- macros work at the token level; they can't know the value of a C variable, only the value of a preprocessor macro).The following modified code works (i.e., prints 10):
The solution is, quite simply, not to do this.
A macro cannot work with values presented minutes, hours, days, years, potentially decades later. A macro is resolved before compilation, and before compilation there is no way of knowing what value
id
holds. During compilation sort of but even then it gets complicated unless the initialiser is trivial and the variable's value can never change.Instead, use a function:
Again, you can make it work at compile-time if
id
is known at compile-time, and indicated as such using the keywordconstexpr
:If neither approach is acceptable, then you must rework your requirements.
But, without knowing what those requirements actually are, we cannot help you to do that.