3

There is a need to create a macro to generate a set of overloadings of a struct specialized by tag and index. I tried the following:

#include <boost/preprocessor/seq/for_each_i.hpp>

template< typename /*tag*/, int /*index*/ >
struct S;

#define GEN(ignored, tilda, index, type_name) \
    template<> struct S< struct BOOST_PP_SEQ_TAIL(type_name), index > \
    { BOOST_PP_SEQ_HEAD(type_name) BOOST_PP_SEQ_TAIL(type_name); };

#if 1
BOOST_PP_SEQ_FOR_EACH_I(GEN, ~, ((int)(i)))
#else
// above should be equiv to:
template<> struct S< struct i, 0 > { int i; };
#endif

int main()
{
    S< i, 0 >{}.i; // check if accessible
}

But get an error:

prog.cc:8:111: error: wrong number of template arguments (1, should be 2)
 #define GEN(ignored, tilda, index, type_name) template<> struct S< struct BOOST_PP_SEQ_TAIL(type_name), index > { BOOST_PP_SEQ_HEAD(type_name) BOOST_PP_SEQ_TAIL(type_name); };
                                                                                                               ^
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:85:66: note: in expansion of macro 'GEN'
 # define BOOST_PP_SEQ_FOR_EACH_I_M_I(r, macro, data, seq, i, sz) macro(r, data, i, BOOST_PP_SEQ_HEAD(seq))
                                                                  ^~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:80:49: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_M_I'
 #    define BOOST_PP_SEQ_FOR_EACH_I_M_IM(r, im) BOOST_PP_SEQ_FOR_EACH_I_M_I(r, im)
                                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:79:45: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_M_IM'
 #    define BOOST_PP_SEQ_FOR_EACH_I_M(r, x) BOOST_PP_SEQ_FOR_EACH_I_M_IM(r, BOOST_PP_TUPLE_REM_5 x)
                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:79:77: note: in expansion of macro 'BOOST_PP_TUPLE_REM_5'
 #    define BOOST_PP_SEQ_FOR_EACH_I_M(r, x) BOOST_PP_SEQ_FOR_EACH_I_M_IM(r, BOOST_PP_TUPLE_REM_5 x)
                                                                             ^~~~~~~~~~~~~~~~~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/control/iif.hpp:32:31: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_M'
 # define BOOST_PP_IIF_1(t, f) t
                               ^
/usr/local/boost-1.62.0/include/boost/preprocessor/repetition/detail/for.hpp:22:37: note: in expansion of macro 'BOOST_PP_FOR_1_C'
 # define BOOST_PP_FOR_1(s, p, o, m) BOOST_PP_FOR_1_C(BOOST_PP_BOOL(p(2, s)), s, p, o, m)
                                     ^~~~~~~~~~~~~~~~
/usr/local/boost-1.62.0/include/boost/preprocessor/cat.hpp:29:34: note: in expansion of macro 'BOOST_PP_FOR_1'
 #    define BOOST_PP_CAT_I(a, b) a ## b
                                  ^
/usr/local/boost-1.62.0/include/boost/preprocessor/control/iif.hpp:32:31: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK_EXEC'
 # define BOOST_PP_IIF_1(t, f) t
                               ^
/usr/local/boost-1.62.0/include/boost/preprocessor/seq/for_each_i.hpp:30:55: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK'
 #    define BOOST_PP_SEQ_FOR_EACH_I(macro, data, seq) BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK(macro, data, seq)
                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:10:1: note: in expansion of macro 'BOOST_PP_SEQ_FOR_EACH_I'
 BOOST_PP_SEQ_FOR_EACH_I(GEN, ~, ((int)(i)))
 ^~~~~~~~~~~~~~~~~~~~~~~
prog.cc:6:8: note: provided for 'template<class, long unsigned int <anonymous> > struct S'
 struct S;
        ^
prog.cc: In function 'int main()':
prog.cc:16:8: error: 'i' was not declared in this scope
     S< i, 0 >{}.i; // check if accessible
        ^
prog.cc:16:13: error: template argument 1 is invalid
     S< i, 0 >{}.i; // check if accessible
             ^

It seems, that struct BOOST_PP_SEQ_TAIL(type_name) part of macro cannot be handled correctly, but why? If I replace first occurrence of BOOST_PP_SEQ_TAIL(type_name) with i, then code compiles fine.

What is the source of an error?

Tomilov Anatoliy
  • 13,614
  • 8
  • 46
  • 134

1 Answers1

2

I removed the #include <cstdint> for brevity's sake, but try compiling with -P -E which will output just the result of the preprocessor run, which is quite valuable when debugging Boost.PP programs.

The output of that is:

template< typename , int >
struct S;
template<> struct S< struct (i), 0 > { int (i); };
int main()
{
    S< i, 0 >{}.i;
}

from which the error is immediately obvious: struct (i) and int (i) are invalid syntax.

This answer might help you with what to do about that.

Here's my solution to this, which is to create my own little tuple-accessing macros:

#include <boost/preprocessor/seq/for_each_i.hpp>

template< typename /*tag*/, int /*index*/ >
struct S;

#define FIRST(a, b) a
#define SECOND(a, b) b

#define GEN(ignored, tilda, index, type_name)                           \
    template<> struct S< struct SECOND type_name, index > \
    { FIRST type_name SECOND type_name; };

#if 1
BOOST_PP_SEQ_FOR_EACH_I(GEN, ~, ((int, i)))
#else
// above should be equiv to:
template<> struct S< struct i, 0 > { int i; };
#endif

int main()
{
    S< i, 0 >{}.i; // check if accessible
}
Community
  • 1
  • 1
SirGuy
  • 10,222
  • 2
  • 32
  • 63
  • `int (i);` is nice syntax even in function parameter list. But seems you find the error source. – Tomilov Anatoliy Jan 12 '17 at 13:49
  • Great solution! – Tomilov Anatoliy Jan 12 '17 at 13:55
  • It is strange, because documentation on boost PP said, that `BOOST_PP_SEQ_TAIL` sould return unparenthesed element of tuple. – Tomilov Anatoliy Jan 12 '17 at 14:02
  • @orient I have no idea why it's not working, other attempts at removing the parenthesis have also failed. I don't know enough about the rules in that case to be able to say whether this is a GCC bug or a Boost.PP bug – SirGuy Jan 12 '17 at 14:11
  • 2
    @Orient Ah! I just noticed in the docs that `BOOST_PP_SEQ_TAIL` expands to `(b)(c)` in the example, which is a sequence again (which makes sense). In your case, even though you have 1 element left in the tail you will still get a sequence with one element in it, which you need to access with `BOOST_PP_SEQ_HEAD`. That's what was happening – SirGuy Jan 12 '17 at 14:22
  • Seems it is a bug of `BOOST_PP_SEQ_TAIL`, which I can replace with `BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_TAIL(*))` – Tomilov Anatoliy Jan 12 '17 at 14:22
  • 1 second difference =) – Tomilov Anatoliy Jan 12 '17 at 14:22
  • 1
    So, *tail* is not a *last*, though *head* is a *first*. – Tomilov Anatoliy Jan 12 '17 at 14:28