pasting "::" and "Foo" does not give a valid preprocessing token
Solution 1
##
is used to bodge two tokens together to make a single token. So something like func##1
would expand to the single token func1
.
Using it here, it tries to bodge together ::
and Foo
to make a single token ::Foo
. As the error says, that's not a valid token. You don't want a single token here; you just want to keep the two tokens separate:
MyNameSpace::func(ds.value())
Solution 2
The ##
works for macros, It doesn't meant to work in a regular code.
You can do it as follows:
#define ADD_NAMESPACE(NS,FUNC) NS##::##FUNC
Now you can use it like this:
ADD_NAMESPACE(std,cout)<<x1<<ADD_NAMESPACE(std,endl);
But you can't do like this:
std ## :: ## cout<<std ## :: ## endl;
You just do:
std::cout<<std::endl;
EDIT
this example worked with gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC):
#include <iostream>
#define ADD_NAMESPACE(NS,FUNC) NS##::##FUNC
int main()
{
ADD_NAMESPACE(std,cout)<<"hello world!"<<ADD_NAMESPACE(std,endl);
return 0;
}
Solution 3
As others have said, ## concatenates two tokens at (or after) the tokenizing stage of compilation:
a##b => (a) ## (b) => (ab)
( possibly invalid, like (::bar) instead of (::), (bar) )
Note, this doesn't send concatenated token identifiers back through the tokenizer, that stage of compilation is already done. What might be messing you up is that these are now tokens, not raw strings anymore.
As I came (late to the party) here looking for the same information, here's a foo.cpp sample if things still don't make sense:
#define FOO(a) Something::a
int main()
{
FOO( bar );
FOO( cat );
return 0;
}
gcc -E foo.cpp produces
# 1 "foo.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "foo.cpp"
int main()
{
Something::bar;
Something::cat;
return 0;
}
cpp_noname
Updated on June 25, 2022Comments
-
cpp_noname almost 2 years
I would like to attach MyNamespace:: to the function defined by the macro:
#define transFunc(func) \ dimensionedScalar func(const dimensionedScalar& ds) \ { \ if (!ds.dimensions().dimensionless()) \ { \ FatalErrorIn(#func "(const dimensionedScalar& ds)") \ << "ds not dimensionless" \ << abort(FatalError); \ } \ \ return dimensionedScalar \ ( \ #func "(" + ds.name() + ')', \ dimless, \ MyNameSpace::##func(ds.value()) \ ); \
}
But When I call
transFunc(Foo)
the compiler throws the following error :
pasting "::" and "Foo" does not give a valid preprocessing token
What is wrong about the way I concatenate tokens above?
-
cpp_noname over 9 yearsbut when it bodges :: and Foo to make ::Foo, which ultimately gives Mynamespace::Foo. I dont see any thing wrong with this...
-
T.C. over 9 years@cpp_noname If you write
Mynamespace::Foo
in normal code, it's three tokens:MyNamespace
,::
andFoo
. -
Lightness Races in Orbit over 9 years@cpp_noname: Tokens are not delimited by spaces necessarily :)
-
Mike Seymour over 9 years@cpp_noname: No, that's parsed as three separate tokens,
Mynamespace
,::
andFoo
, which between them form a valid C++ expression.::Foo
, as a single token, is not valid. That's what the (incorrect) use of##
tries to create. -
Anton Samsonov almost 9 yearsWhich compiler does that succeed with? For example, GCC 4.8.3 throws the same error as in original post, but now regarding
NS
and::
; however, simply writingMyNameSpace::func(ds.value())
as in the answer by Mike Seymour somehow works — despite that simplified parsers, like KDevelop's built-in analyzer, understands that literally. -
SHR about 6 years@AntonSamsonov I added full example with gcc version. If you've got stray ## error, I think you tried the
std ## :: ## cout<<std ## :: ## endl;
which specified under But you can't do like this: