P
Paul Mensonides
"Andrei Alexandrescu (See Website for Email)"
You'd just have to parenthesize types that contain open commas:
TYPELIST((vector<int, my_allocator<int> >), vector<float>)
The DECODE macro in the example removes parentheses if they exist. E.g.
CHAOS_PP_DECODE(int) // int
CHAOS_PP_DECODE((int)) // int
Using parentheses is, of course, only necessary for types that contain open
commas. (There is also a ENCODE macro that completes the symmetry, but it is
unnecessary.)
There are also a several other alternatives. It is possible to pass a type
through a system of macros without the system of macros being intrusively
modified (with DECODE or similar). This, in Chaos terminology, is a "rail". It
is a macro invocation that effectively won't expand until some context is
introduced. E.g.
#include <chaos/preprocessor/punctuation/comma.h>
#define A(x) B(x)
#define B(x) C(x)
#define C(x) D(x)
#define D(x) x
A(CHAOS_PP_COMMA())
This will error with too many arguments to B. However, the following disables
evaluation of COMMA() until after the system "returns" from A:
#include <chaos/preprocessor/punctuation/comma.h>
#include <chaos/preprocessor/recursion/rail.h>
#define A(x) B(x)
#define B(x) C(x)
#define C(x) D(x)
#define D(x) x
CHAOS_PP_WALL(A(
CHAOS_PP_UNSAFE_RAIL(CHAOS_PP_COMMA)()
))
(There is also CHAOS_PP_RAIL that is similar, but getting into the difference
here is too complex a subject.)
In any case, the expansion of COMMA is inhibited until it reaches the context
established by WALL. The same thing can be achieved for types non-intrusively.
Chaos has two rail macros designed for this purpose, TYPE and TYPE_II. The
first, TYPE, is the most syntactically clean, but is only available with
variadics:
#include <chaos/preprocessor/facilities/type.h>
#include <chaos/preprocessor/recursion/rail.h>
#define A(x) B(x)
#define B(x) C(x)
#define C(x) D(x)
#define D(x) x
CHAOS_PP_WALL(A(
CHAOS_PP_TYPE(std:air<int, int>)
))
// std:air<int, int>
The second, TYPE_II, is more syntactically verbose, but it works even without
variadics without counting commas:
#include <chaos/preprocessor/facilities/type.h>
#include <chaos/preprocessor/recursion/rail.h>
#define A(x) B(x)
#define B(x) C(x)
#define C(x) D(x)
#define D(x) x
CHAOS_PP_WALL(A(
CHAOS_PP_TYPE_II(CHAOS_PP_BEGIN std:air<int, int> CHAOS_PP_END)
))
// std:air<int, int>
Thus, you *could* make a typelist using rails such as this to protect
open-comma'ed types, but for typelists (which inherently deal with types), it
would be pointless. Rails are more useful when some arbitrary data that you
need to pass around happens to be a type, but doesn't necessarily have to be.
Regards,
Paul Mensonides
Cool. Before continuing the discussion, I have a simple question - how does
your implementation cope with commas in template types, for example:
TYPELIST(vector<int, my_allocator<int> >, vector<float>)
would correctly create a typelist of two elements? If not, what steps do I
need to take to creat such a typelists (aside from a typedef)?
You'd just have to parenthesize types that contain open commas:
TYPELIST((vector<int, my_allocator<int> >), vector<float>)
The DECODE macro in the example removes parentheses if they exist. E.g.
CHAOS_PP_DECODE(int) // int
CHAOS_PP_DECODE((int)) // int
Using parentheses is, of course, only necessary for types that contain open
commas. (There is also a ENCODE macro that completes the symmetry, but it is
unnecessary.)
There are also a several other alternatives. It is possible to pass a type
through a system of macros without the system of macros being intrusively
modified (with DECODE or similar). This, in Chaos terminology, is a "rail". It
is a macro invocation that effectively won't expand until some context is
introduced. E.g.
#include <chaos/preprocessor/punctuation/comma.h>
#define A(x) B(x)
#define B(x) C(x)
#define C(x) D(x)
#define D(x) x
A(CHAOS_PP_COMMA())
This will error with too many arguments to B. However, the following disables
evaluation of COMMA() until after the system "returns" from A:
#include <chaos/preprocessor/punctuation/comma.h>
#include <chaos/preprocessor/recursion/rail.h>
#define A(x) B(x)
#define B(x) C(x)
#define C(x) D(x)
#define D(x) x
CHAOS_PP_WALL(A(
CHAOS_PP_UNSAFE_RAIL(CHAOS_PP_COMMA)()
))
(There is also CHAOS_PP_RAIL that is similar, but getting into the difference
here is too complex a subject.)
In any case, the expansion of COMMA is inhibited until it reaches the context
established by WALL. The same thing can be achieved for types non-intrusively.
Chaos has two rail macros designed for this purpose, TYPE and TYPE_II. The
first, TYPE, is the most syntactically clean, but is only available with
variadics:
#include <chaos/preprocessor/facilities/type.h>
#include <chaos/preprocessor/recursion/rail.h>
#define A(x) B(x)
#define B(x) C(x)
#define C(x) D(x)
#define D(x) x
CHAOS_PP_WALL(A(
CHAOS_PP_TYPE(std:air<int, int>)
))
// std:air<int, int>
The second, TYPE_II, is more syntactically verbose, but it works even without
variadics without counting commas:
#include <chaos/preprocessor/facilities/type.h>
#include <chaos/preprocessor/recursion/rail.h>
#define A(x) B(x)
#define B(x) C(x)
#define C(x) D(x)
#define D(x) x
CHAOS_PP_WALL(A(
CHAOS_PP_TYPE_II(CHAOS_PP_BEGIN std:air<int, int> CHAOS_PP_END)
))
// std:air<int, int>
Thus, you *could* make a typelist using rails such as this to protect
open-comma'ed types, but for typelists (which inherently deal with types), it
would be pointless. Rails are more useful when some arbitrary data that you
need to pass around happens to be a type, but doesn't necessarily have to be.
Regards,
Paul Mensonides