pasting "::" and "Foo" does not give a valid preprocessing token

10,561

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;
}
Share:
10,561
cpp_noname
Author by

cpp_noname

Updated on June 25, 2022

Comments

  • cpp_noname
    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
    cpp_noname over 9 years
    but when it bodges :: and Foo to make ::Foo, which ultimately gives Mynamespace::Foo. I dont see any thing wrong with this...
  • T.C.
    T.C. over 9 years
    @cpp_noname If you write Mynamespace::Foo in normal code, it's three tokens: MyNamespace, :: and Foo.
  • Lightness Races in Orbit
    Lightness Races in Orbit over 9 years
    @cpp_noname: Tokens are not delimited by spaces necessarily :)
  • Mike Seymour
    Mike Seymour over 9 years
    @cpp_noname: No, that's parsed as three separate tokens, Mynamespace, :: and Foo, 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
    Anton Samsonov almost 9 years
    Which 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 writing MyNameSpace::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
    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: