Вот моя попытка. К сожалению, он опирается на макросы variadic, которые являются функцией C99 / C ++ 1x. Но работает в GCC.
#include <boost/foreach.hpp>
#include <boost/type_traits.hpp>
#include <iostream>
#define SEQ_FOR_EACH(D, ...) \
if(bool c = false) ; else \
for(boost::remove_reference<boost::function_traits<void(D)> \
::arg1_type>::type _t[] = __VA_ARGS__; \
!c; c = true) \
BOOST_FOREACH(D, _t)
int main() {
SEQ_FOR_EACH(std::string &v, { "hello", "doctor" }) {
std::cout << v << std::endl;
}
}
Обратите внимание, что вы также можете перебирать ссылочную переменную, чтобы избежать бесполезного копирования. Вот пример использования boost.preprocessor
и синтаксиса (a)(b)...
, компиляция до одного и того же кода после этапа предварительной обработки.
#define SEQ_FOR_EACH(D, SEQ) \
if(bool c = false) ; else \
for(boost::remove_reference<boost::function_traits<void(D)> \
::arg1_type>::type _t[] = { BOOST_PP_SEQ_ENUM(SEQ) }; \
!c; c = true) \
BOOST_FOREACH(D, _t)
int main() {
SEQ_FOR_EACH(std::string &v, ("hello")("doctor")) {
std::cout << v << std::endl;
}
}
Хитрость заключается в том, чтобы собрать тип функции, который имеет в качестве параметра переменную перечисления, и получить тип этого параметра. Тогда boost::remove_reference
удалит любую ссылку. Первая используемая версия boost::decay
. Но это также преобразовало бы массивы в указатели, которые я нашел не то, что иногда нужно. Полученный тип затем используется как тип элемента массива.
Для использования в шаблонах, где переменная перечислителя имеет зависимый тип, вам придется использовать другой макрос, который ставит typename
перед boost::remove_reference
и boost::function_traits
. Может назвать это SEQ_FOR_EACH_D
(D == в зависимости).