Discussion:
Concatination creates invalid preprocessor parameter?
(too old to reply)
Noah Roberts
2011-01-11 18:15:57 UTC
Permalink
#define STR_HELPER(s) #s
#define STRINGIZE(s) STR_HELPER(s)

// BOOST_PP_CAT also fails for same reason.
#define MACRO(s1,s2) STRINGIZE(s1 ## s2)

#include <iostream>
int main()
{
std::cout << STRINGIZE(hello(int,int)) << std::endl; // fine.
std::cout << MACRO(hello, (int,int)) << std::endl; // error.
}

Error = concatination of 'hello' and '(' creates invalid preprocessor
token.

Both versions work fine in MSVC++. G++ hates it.

What's the deal? Who's wrong and why?

thx
--
http://crazyeddiecpp.blogspot.com/
Alf P. Steinbach /Usenet
2011-01-11 18:23:30 UTC
Permalink
Post by Noah Roberts
#define STR_HELPER(s) #s
#define STRINGIZE(s) STR_HELPER(s)
// BOOST_PP_CAT also fails for same reason.
#define MACRO(s1,s2) STRINGIZE(s1 ## s2)
#include<iostream>
int main()
{
std::cout<< STRINGIZE(hello(int,int))<< std::endl; // fine.
std::cout<< MACRO(hello, (int,int))<< std::endl; // error.
}
Error = concatination of 'hello' and '(' creates invalid preprocessor
token.
Both versions work fine in MSVC++. G++ hates it.
What's the deal? Who's wrong
Visual C++ wrong, g++ right.
Post by Noah Roberts
and why?
Standard requires valid preprocessor token.

This makes it difficult to create directory paths.

Not easy to say why the proprocessor is so incredibly primitive and limited, but
consider that if it were more powerful then it would probably be used more
(which would be undesireable).


Cheers
--
blog at <url: http://alfps.wordpress.com>
Noah Roberts
2011-01-11 20:00:27 UTC
Permalink
Post by Alf P. Steinbach /Usenet
Post by Noah Roberts
#define STR_HELPER(s) #s
#define STRINGIZE(s) STR_HELPER(s)
// BOOST_PP_CAT also fails for same reason.
#define MACRO(s1,s2) STRINGIZE(s1 ## s2)
#include<iostream>
int main()
{
std::cout<< STRINGIZE(hello(int,int))<< std::endl; // fine.
std::cout<< MACRO(hello, (int,int))<< std::endl; // error.
}
Error = concatination of 'hello' and '(' creates invalid preprocessor
token.
Both versions work fine in MSVC++. G++ hates it.
What's the deal? Who's wrong
Visual C++ wrong, g++ right.
Post by Noah Roberts
and why?
Standard requires valid preprocessor token.
This makes it difficult to create directory paths.
Not easy to say why the proprocessor is so incredibly primitive and limited, but
consider that if it were more powerful then it would probably be used more
(which would be undesireable).
Cheers
What's invalid about "hello(int,int)"? Why is it accepted when you
don't concat?


Comeau also gobbles it up even in strict, no-extensions mode.
--
http://crazyeddiecpp.blogspot.com/
Noah Roberts
2011-01-11 20:06:42 UTC
Permalink
Post by Noah Roberts
Post by Noah Roberts
#define STR_HELPER(s) #s
#define STRINGIZE(s) STR_HELPER(s)
// BOOST_PP_CAT also fails for same reason.
#define MACRO(s1,s2) STRINGIZE(s1 ## s2)
#include<iostream>
int main()
{
std::cout<< STRINGIZE(hello(int,int))<< std::endl; // fine.
std::cout<< MACRO(hello, (int,int))<< std::endl; // error.
}
What's invalid about "hello(int,int)"? Why is it accepted when you
don't concat?
Comeau also gobbles it up even in strict, no-extensions mode.
Actually, put a different way, if "hello(int,int)" is not a valid
preprocessor token then why is it able to form one in the first output
line in main()? There's a certain well known and often used C++ UI
library that uses this sort of syntax.
--
http://crazyeddiecpp.blogspot.com/
Alf P. Steinbach /Usenet
2011-01-11 20:20:25 UTC
Permalink
Post by Noah Roberts
Post by Alf P. Steinbach /Usenet
Post by Noah Roberts
#define STR_HELPER(s) #s
#define STRINGIZE(s) STR_HELPER(s)
// BOOST_PP_CAT also fails for same reason.
#define MACRO(s1,s2) STRINGIZE(s1 ## s2)
#include<iostream>
int main()
{
std::cout<< STRINGIZE(hello(int,int))<< std::endl; // fine.
std::cout<< MACRO(hello, (int,int))<< std::endl; // error.
}
Error = concatination of 'hello' and '(' creates invalid preprocessor
token.
Both versions work fine in MSVC++. G++ hates it.
What's the deal? Who's wrong
Visual C++ wrong, g++ right.
Post by Noah Roberts
and why?
Standard requires valid preprocessor token.
This makes it difficult to create directory paths.
Not easy to say why the proprocessor is so incredibly primitive and limited, but
consider that if it were more powerful then it would probably be used more
(which would be undesireable).
Cheers
What's invalid about "hello(int,int)"?
It consists of 6 preprocessing tokens: "hello", "(", "int", ",", "int" and ")".
Post by Noah Roberts
Why is it accepted when you don't concat?
§16.3/10 effectively defines a preprocessor actual argument as a sequence of
preprocessing tokens. Such a sequence can contain comma tokens within
parentheses, and can otherwise not contain comma tokens.

§16.3.3/3 requires the result of ## to be single preprocessing token, "otherwise
the behavior is undefined".
Post by Noah Roberts
Comeau also gobbles it up even in strict, no-extensions mode.
Well, with UB it can do anything. ;-)


Cheers & hth.,

- Alf
--
blog at <url: http://alfps.wordpress.com>
James Kanze
2011-01-12 11:03:02 UTC
Permalink
Post by Noah Roberts
Post by Alf P. Steinbach /Usenet
Post by Noah Roberts
#define STR_HELPER(s) #s
#define STRINGIZE(s) STR_HELPER(s)
// BOOST_PP_CAT also fails for same reason.
#define MACRO(s1,s2) STRINGIZE(s1 ## s2)
#include<iostream>
int main()
{
std::cout<< STRINGIZE(hello(int,int))<< std::endl; // fine.
std::cout<< MACRO(hello, (int,int))<< std::endl; // error.
}
Error = concatination of 'hello' and '(' creates invalid preprocessor
token.
Both versions work fine in MSVC++. G++ hates it.
What's the deal? Who's wrong
Visual C++ wrong, g++ right.
Both are right. It's undefined behavior, and anything the
compiler does when there is undefined behavior is right.
Post by Noah Roberts
Post by Alf P. Steinbach /Usenet
Post by Noah Roberts
and why?
Standard requires valid preprocessor token.
This makes it difficult to create directory paths.
G++ solves this by allowing concatenated string literals to be
used as a directory path. Although I can't find anything in the
standard which supports this, it also works with VC++ and with
Sun CC, so I guess it's sort of a defacto standard.
Post by Noah Roberts
Post by Alf P. Steinbach /Usenet
Not easy to say why the proprocessor is so incredibly
primitive and limited, but consider that if it were more
powerful then it would probably be used more (which would be
undesireable).
What's invalid about "hello(int,int)"? Why is it accepted when you
don't concat?
With the "...", there's nothing wrong with it. Without the
"...", as the results of ##, it's not a single token, so
undefined behavior results.
Post by Noah Roberts
Comeau also gobbles it up even in strict, no-extensions mode.
It used to be a traditional solution; preprocessors generally
substitute (and concatenate) text strings, not tokens. I think
g++ introduced the check (it worked with older versions of gcc)
just to piss people off. Formally, it's undefined behavior: the
C committee wanted to allow preprocessors to work at the token
level. But in practice, no preprocessor has ever done this, and
your example had always worked, everywhere. Until gcc decided
to break it.

As Alf pointed out, it's a pain when it comes to generating
include paths. (In my own code, I use things like:
#include GB_dependentInclude(syst,"someFile.h")
to pick up an include which depends on the system, for example.
And there's a fair amount of token pasting going on in
GB_dependentInclude. Except that I don't token paste;
I concatenate string literals. Which shouldn't work, if you
read the standard literally, but in fact does, at least with all
of the compilers I've encountered.)

--
James Kanze

Loading...