__VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: Владислав Курмаз Украина http://tis-method.org/
Дата: 12.08.11 06:43
Оценка:
Доброго времени суток.

Необходимо написать макрос для упрощения задания частичных специализаций шаблона < P1 > .. <P1, ..., P10>

template < typename P1, typename P2, typename P2, template < typename, typename, typename > class C >
struct term_< C< P1, P2, P3 > >
{
    typedef term_< boost::mpl::identity< C< P1, P2, P3 > > > cls_t;
    typedef func_param_< LOKI_TYPELIST_2( P1, P2, P3 ), 0 > params_t;
    ...
};

Прототип
#define DEF_PARAM( n, ... ) LOKI_TYPELIST_##n( __VA_ARGS__ )

Использование
DEF_PARAM( 3, P1, P2, P3 );

Вывод препроцессора
::Loki::Typelist<P1, P2, P3, ::Loki::Typelist<, ::Loki::Typelist<, ::Loki::NullType> > >;

соответственно отличается от желаемого
::Loki::Typelist<P1, ::Loki::Typelist<P2, ::Loki::Typelist< P3, ::Loki::NullType> > >;

танцы с бубном не помогли и хочется спросить у участников форума. Есть ли решение у данной задачи?
Re: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: jazzer Россия Skype: enerjazzer
Дата: 12.08.11 07:12
Оценка: 2 (1)
Здравствуйте, Владислав Курмаз, Вы писали:

ВК>Необходимо написать макрос для упрощения задания частичных специализаций шаблона < P1 > .. <P1, ..., P10>


ВК>танцы с бубном не помогли и хочется спросить у участников форума. Есть ли решение у данной задачи?

На вариадиках нормального решения нету, так как хоть они и есть, рекурсивный обход списка аргументов не поддерживается.
Народ в бусте делает костыль под названием VMD, но это все равно будет костыль.

Но это очень просто делается на Boost.Preprocessor:
#define DECL(z, n, text)                                                               \
template < BOOST_PP_ENUM_PARAMS(n, typename P)                                         \
         , template < BOOST_PP_ENUM_PARAMS(n, typename BOOST_PP_INTERCEPT) > class C > \
struct term_< C< BOOST_PP_ENUM_PARAMS(n, P) > >                                        \
{                                                                                      \
    typedef term_< boost::mpl::identity< C< BOOST_PP_ENUM_PARAMS(n, P) > > > cls_t;    \
    typedef func_param_< LOKI_TYPELIST_2( BOOST_PP_ENUM_PARAMS(n, P) ), 0 > params_t;  \
    ...                                                                                \
};                                                                                     \

BOOST_PP_REPEAT_FROM_TO(1,11,DECL,_)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: Владислав Курмаз Украина http://tis-method.org/
Дата: 12.08.11 07:36
Оценка:
Здравствуйте, jazzer, Вы писали:
Спасибо, буду пробовать.

Хотел уточнить один момент.
Меня интересует строка
    typedef func_param_< LOKI_TYPELIST_???( BOOST_PP_ENUM_PARAMS(n, P) ), 0 > params_t;  \

значение ??? Должно меняться от 1 до 10, LOKI_TYPELIST_1 .. LOKI_TYPELIST_10. Это возможно будет реализовать через Boost.Preprocessor?
Re[3]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: jazzer Россия Skype: enerjazzer
Дата: 12.08.11 08:07
Оценка: 2 (1)
Здравствуйте, Владислав Курмаз, Вы писали:

ВК>Здравствуйте, jazzer, Вы писали:

ВК>Спасибо, буду пробовать.

ВК>Хотел уточнить один момент.

ВК>Меня интересует строка
ВК>
ВК>    typedef func_param_< LOKI_TYPELIST_???( BOOST_PP_ENUM_PARAMS(n, P) ), 0 > params_t;  \
ВК>

ВК>значение ??? Должно меняться от 1 до 10, LOKI_TYPELIST_1 .. LOKI_TYPELIST_10. Это возможно будет реализовать через Boost.Preprocessor?
Можно, само по себе это просто: LOKI_TYPELIST_##n
Но т.к. нам нужно раскрыть аргументы до того, как применять LOKI_TYPELIST_3, и нужно, чтоб их было именно 3, а скобки у нас стоят вокруг BOOST_PP_ENUM_PARAMS, а не внутри, то придется извратиться.
Самый простой способ — с дополнительной макрой, в которой как раз эти скобки и будут:
#define P_ARGS(n) ( BOOST_PP_ENUM_PARAMS(n, P) )
...
    typedef func_param_< BOOST_PP_EXPAND( LOKI_TYPELIST_##n P_ARGS(n) ), 0 > params_t;   \


Есть способ без дополнительной макры, но он нечитабелен почти (фактически я эмулирую вызов дополнительной макры через IDENTITY):
    typedef func_param_< BOOST_PP_EXPAND( LOKI_TYPELIST_##n \
                                          BOOST_PP_IDENTITY( (BOOST_PP_ENUM_PARAMS(n, P)) )() ) \
                       , 0 > params_t;   \
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: Владислав Курмаз Украина http://tis-method.org/
Дата: 12.08.11 10:06
Оценка:
Соответственно, вот такое получилось решение для того чтобы помирить всё с LOKI_TYPELIST_?
#ifndef Z3D_TYPE_NAME_PARAMS
#define Z3D_TYPE_NAME_PARAMS 11
#endif

#ifndef Z3D_TYPE_NAME_TEMPLATE_PARAMS
#    define Z3D_TYPE_NAME_TEMPLATE_PARAMS Z3D_TYPE_NAME_PARAMS
#endif

#define Z3D_TYPE_NAME_DEF_TEMPLATE_ARGS(n) (BOOST_PP_ENUM_PARAMS(n, P))

#define Z3D_TYPE_NAME_DEF_TEMPLATE(z, n, text)                                               \
template < BOOST_PP_ENUM_PARAMS(n, typename P)                                               \
         , template < BOOST_PP_ENUM_PARAMS(n,typename BOOST_PP_INTERCEPT ) > class C >       \
struct term_< C< BOOST_PP_ENUM_PARAMS(n, P) > >                                              \
{                                                                                            \
    typedef term_< boost::mpl::identity< C< BOOST_PP_ENUM_PARAMS(n,P) > > > cls_t;             \
    typedef func_param_< LOKI_TYPELIST_##n Z3D_TYPE_NAME_DEF_TEMPLATE_ARGS(n), 0 > params_t;   \
    ...
};

BOOST_PP_REPEAT_FROM_TO( 1, Z3D_TYPE_NAME_TEMPLATE_PARAMS, Z3D_TYPE_NAME_DEF_TEMPLATE, _ )
Re[5]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: jazzer Россия Skype: enerjazzer
Дата: 12.08.11 10:27
Оценка: 2 (1)
Здравствуйте, Владислав Курмаз, Вы писали:

ВК>Соответственно, вот такое получилось решение для того чтобы помирить всё с LOKI_TYPELIST_?

ВК>
ВК>    typedef func_param_< LOKI_TYPELIST_##n Z3D_TYPE_NAME_DEF_TEMPLATE_ARGS(n), 0 > params_t;   \
ВК>


BOOST_PP_EXPAND потерял. Без него LOKI_TYPELIST_##n не раскроется.

Кстати, можно эту генерацию слегка ускорить, если заюзать BOOST_PP_ENUM_PARAMS_Z вместо BOOST_PP_ENUM_PARAMS:
#define Z3D_TYPE_NAME_DEF_TEMPLATE_ARGS(z,n) (BOOST_PP_ENUM_PARAMS_Z(z, n, P))

#define Z3D_TYPE_NAME_DEF_TEMPLATE(z, n, text)                                                                \
template < BOOST_PP_ENUM_PARAMS_Z(z, n, typename P)                                                           \
         , template < BOOST_PP_ENUM_PARAMS_Z(z, n,typename BOOST_PP_INTERCEPT ) > class C >                   \
struct term_< C< BOOST_PP_ENUM_PARAMS_Z(z, n, P) > >                                                          \
{                                                                                                             \
  typedef term_< boost::mpl::identity< C< BOOST_PP_ENUM_PARAMS_Z(z, n,P) > > > cls_t;                         \
  typedef func_param_< BOOST_PP_EXPAND(LOKI_TYPELIST_##n Z3D_TYPE_NAME_DEF_TEMPLATE_ARGS(z,n)), 0 > params_t; \
  ...
};
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: SX Россия  
Дата: 13.08.11 07:21
Оценка: 2 (1)
Здравствуйте, Владислав Курмаз, Вы писали:

ВК>Прототип

ВК>
ВК>#define DEF_PARAM( n, ... ) LOKI_TYPELIST_##n( __VA_ARGS__ )
ВК>

ВК>Использование
ВК>
ВК>DEF_PARAM( 3, P1, P2, P3 );    
ВК>


А если попробовать так:
#define INVOKE_MACROS( x ) x
#define DEF_PARAM( n, ... ) INVOKE_MACROS( LOKI_TYPELIST_##n( __VA_ARGS__ ) )


Работает под MSVC 2010 и GCC 4.5.
Re[2]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: SX Россия  
Дата: 13.08.11 07:46
Оценка: 3 (1)
Можно пойти немного дальше — не задавать количество параметров (первый аргумент).
Т.е. вместо
DEF_PARAM( 3, P1, P2, P3 );

использовать следующую запись:
DEF_PARAM( P1, P2, P3 );


Этого можно добиться, используя следующую реализацию:
#define CAT(x,y) CAT_A(x, y)
#define CAT_A(x,y) x##y

#define VA_SIZE(...) INVOKE_MACROS( VA_GET_SIZE( __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, _ ) )
#define VA_GET_SIZE(_0,_1_,_2,_3,_4_,_5,_6,_7,_8,_9,n,...) n

#define INVOKE_MACROS( x ) x

#define DEF_PARAM(...) INVOKE_MACROS( CAT(LOKI_TYPELIST_, VA_SIZE(__VA_ARGS__)) (__VA_ARGS__) )


Ограничение: количество параметров от 1 до 10.
Работает под MSVC 2010 и GCC 4.5.
Re[2]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: Masterkent  
Дата: 13.08.11 09:58
Оценка: 2 (1)
jazzer:

J>На вариадиках нормального решения нету, так как хоть они и есть, рекурсивный обход списка аргументов не поддерживается.


А можно поподробнее описать суть проблемы с variadic-ами? Если я правильно понял задачу, то она, вроде, решается довольно легко:

http://ideone.com/mfPjm
Re[2]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: Владислав Курмаз Украина http://tis-method.org/
Дата: 13.08.11 10:05
Оценка:
Здравствуйте, SX, Вы писали:


SX>
SX>#define INVOKE_MACROS( x ) x
SX>#define DEF_PARAM( n, ... ) INVOKE_MACROS( LOKI_TYPELIST_##n( __VA_ARGS__ ) )
SX>

SX>Работает под MSVC 2010 и GCC 4.5.
Да, спасибо. Вроде бы пробовал такое решение, но что-то у меня тогда не срослось
Re[3]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: Владислав Курмаз Украина http://tis-method.org/
Дата: 13.08.11 10:12
Оценка:
Здравствуйте, SX, Вы писали:


SX>
SX>#define VA_SIZE(...) INVOKE_MACROS( VA_GET_SIZE( __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, _ ) )
SX>#define VA_GET_SIZE(_0,_1_,_2,_3,_4_,_5,_6,_7,_8,_9,n,...) n
SX>

Ох, какое красивое решение, со сдвигом параметров!!! Возьму на заметку.
Re[3]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: Владислав Курмаз Украина http://tis-method.org/
Дата: 13.08.11 10:21
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>jazzer:


J>>На вариадиках нормального решения нету, так как хоть они и есть, рекурсивный обход списка аргументов не поддерживается.


M>А можно поподробнее описать суть проблемы с variadic-ами? Если я правильно понял задачу, то она, вроде, решается довольно легко:


M>http://ideone.com/mfPjm


Решение уже подсказали, даже два.
Задача была именно в автоматизации задания частичных специализаций, чтобы не копипастить в коде что-то типа этого
template < typename P0 > class{ ... };
...
template < typename P0, ..., typename P14 > class{ ... };

плюс подружить это с макросом LOKI_TYPELIST_? и всё это в базисе текущего стандарта.

Но с variadic-ами тоже попробую. Спасибо.
Re[4]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: jazzer Россия Skype: enerjazzer
Дата: 13.08.11 10:52
Оценка:
Здравствуйте, Владислав Курмаз, Вы писали:

ВК>Здравствуйте, SX, Вы писали:



SX>>
SX>>#define VA_SIZE(...) INVOKE_MACROS( VA_GET_SIZE( __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, _ ) )
SX>>#define VA_GET_SIZE(_0,_1_,_2,_3,_4_,_5,_6,_7,_8,_9,n,...) n
SX>>

ВК>Ох, какое красивое решение, со сдвигом параметров!!! Возьму на заметку.

В вышеупомянутой VMD примерно такой подход и использется, только до 256
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: Владислав Курмаз Украина http://tis-method.org/
Дата: 13.08.11 10:58
Оценка:
Здравствуйте, jazzer, Вы писали:

J>В вышеупомянутой VMD примерно такой подход и использется, только до 256

У VDM тоже есть ограничение на невозможность отследить 0 аргументов? или там есть всё-таки решение?
Re[3]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: jazzer Россия Skype: enerjazzer
Дата: 13.08.11 10:59
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>jazzer:


J>>На вариадиках нормального решения нету, так как хоть они и есть, рекурсивный обход списка аргументов не поддерживается.


M>А можно поподробнее описать суть проблемы с variadic-ами?

Я о variadic macros, не о variadic templates. У variadic templates таких проблем нет. А вот variadic macros — довольное бесполезное изделие, когда нет средств поэлементной обработки __VA_ARGS__.

M>Если я правильно понял задачу, то она, вроде, решается довольно легко:

M>http://ideone.com/mfPjm
+1. Если поддерживаются variadic templates, и если LOKI_TYPELIST_N делает то, о чем мы оба думаем, то можно все решить вообще без привлечения препроцессора и макросов LOKI.
Просто поддержке variadic macros уже сто лет в обед, а variadic templates — все еще довольно новая фишка, которая есть далеко не везде, а где есть, не всегда хорошо реализована.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: jazzer Россия Skype: enerjazzer
Дата: 13.08.11 11:00
Оценка:
Здравствуйте, Владислав Курмаз, Вы писали:

ВК>Здравствуйте, jazzer, Вы писали:


J>>В вышеупомянутой VMD примерно такой подход и использется, только до 256

ВК>У VDM тоже есть ограничение на невозможность отследить 0 аргументов? или там есть всё-таки решение?

не помню, сорри. Гугл в помощь.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: __VA_ARGS__ и LOKI_TYPELIST_? (вложенные define-ы)
От: SX Россия  
Дата: 13.08.11 11:31
Оценка:
Здравствуйте, Владислав Курмаз, Вы писали:

ВК>Здравствуйте, jazzer, Вы писали:


J>>В вышеупомянутой VMD примерно такой подход и использется, только до 256

ВК>У VDM тоже есть ограничение на невозможность отследить 0 аргументов? или там есть всё-таки решение?

Я не использовал VMD (честно, не знаю что это).
Но для 0 аргументов придумалось следующее решение:

#define VA_OB (
#define VA_CB )
#define VA_SPEC() 1,2,3,4,5,6,7,8,9,10,11
#define VA_SIZE(...) INVOKE_MACROS( VA_GET_SIZE VA_OB INVOKE_MACROS(VA_SPEC##__VA_ARGS__()), 0, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 VA_CB )
#define VA_GET_SIZE(_,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,n,...) n

#define INVOKE_MACROS( ... ) INVOKE_MACROS_A( __VA_ARGS__ )
#define INVOKE_MACROS_A( ... ) __VA_ARGS__


Теперь конструкция VA_SIZE() возвращает 0.
Наверное, можно реализовать и более эффективно. Нужно подумать.
Текущая реализация может принимать от 0 до 10 аргументов.

Решение работает на MSVC2010 и GCC 4.5.

С уважением, Сергей.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.