Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2003-04-17 16:17:26


>From: "Paul Mensonides" <pmenso57_at_[hidden]>

> Terje Slettebø wrote:
> > Is there some way (using PP-lib, or whatever), to pass a template-id
> > with more than one parameter (thus, it contains at least one comma),
> > to a macro?
> >
> > E.g.:
> >
> > #define TEST(a) test<a> t;
> >
> > TEST(std::pair<char,int>) // Won't work
> >
> > Maybe some sort of variation of BOOST_PP_IDENTITY:
> >
> > #define BOOST_PP_IDENTITY1(a) a
> > #define BOOST_PP_IDENTITY2(a,b) a,b
> > #define BOOST_PP_IDENTITY3(a,b,c) a,b,c
> >
> > etc.
> >
> > TEST(BOOST_PP_IDENTITY2(std::pair<char,int>)) // Now ok
>
> I'll answer all three of these emails at once, since they are about the
same
> thing. First, the above will cause problems, specifically problems like
this:
>
> #define T1(a) T2(a)
> #define T2(a) test<a> t;
>
> #define IDENTITY2(a, b) a, b
>
> T1(IDENTITY2(std::pair<char, int>)) // error
>
> I.e. by the time that T2 is invoked, IDENTITY2 has already expanded, which
> yields too many arguments to T2.

Right. However, for simple use (only one level of macro expansion), this
works, and has the advantage of being simple and non-intrusive to use.

> What we need is a general solution and a set
> of conventions for passing types. This is difficult without variadics to
do
> with the preprocessor itself. Specifically, you have to use the core
language:
>
> template<class T> struct wrap {
> typedef T type;
> };
>
> template<class T> struct wrap<void (T)> {
> typedef T type;
> };
>
> #define TYPE(x) wrap<void x>::type
>
> TYPE((int)) // okay
> TYPE((std::pair<char, int>)) // okay
>
> However, this has its own problems. Specifically, it is using function
types to
> store the type--which is inside parentheses and therefore protected from
the
> preprocessor. The use of function types with cause certain things to
error:
>
> TYPE(( void )) // error
> TYPE(( int (int, int) )) // function type altered to pointer-to-function
> TYPE(( int[2] )) // array altered to pointer

Right. It's similar to Aleksey's "round lambda".

> There is only one other language construct that might be of use here:
> pointers-to-members. Specifically, it is parenthesized, yet does not
undergo
> promotion/alteration when used in a parameter list. However, it is
intrusive:
>
> template<class> struct wrap;
> template<class T> struct wrap<void (T::*)(void)> {
> typedef T type;
> };
>
> #define TYPE(x) wrap<void T(void)>::type
>
> TYPE(( std::pair<int, int>::* ))
> ^^^
> Also, this cannot be used for non-class types--which can still have commas
in
> them:
>
> template<class T, class U> struct typelist {
> typedef T head;
> typedef U tail;
> };
>
> TYPE(( typelist<int, nil>::head::* )) // error
>
> So, without variadic macros, there is no "good" solution. Instead, you
have to
> resort to hacks that require you to know the number of unbound commas in
the
> type:
>
> #define IN(s, x) (s) x
> #define OUT(x) BOOST_PP_TUPLE_REM x
>
> #define M1(type) M2(type)
> #define M2(type) OUT(type)
>
> MACRO( IN(2, (std::pair<int, int>)) )

I'm not sure how this latter solution could be used. How could MACRO
retrieve the type being passed?

Thanks. :)

Regards,

Terje


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk