Я пытаюсь построить макрос
#define F(...) ???
, который расширит следующую конструкцию
#define A 1
#define B 2
#define C 3
#define D 4
F(A, B, C, D)
в следующий код:
1, "A", 2, "B", 3, "C", 4, "D"
I Я пытался использовать Boost.Preprocessor, но, похоже, ему не хватает требуемой функциональности:
#define Q(r, data, elem) elem, BOOST_PP_STRINGIZE(elem),
#define F(...) BOOST_PP_SEQ_FOR_EACH(Q,,BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
F(A, B, C, D)
расширяется до 1, "1", 2, "2", 3, "3", 4, " 4 ", чего я не хочу достичь. Это происходит внутри BOOST_PP_VARIADIC_TO_SEQ, поэтому я не могу по-настоящему контролировать его.
Есть ли простой способ сделать это без перегруженных макросов или с перегруженными макросами, но в уже существующей библиотеке?
EDIT: I ' м с использованием C ++, поэтому решения C и C ++ хороши
EDIT2:
Это чистое решение C ++ 17
#include <iostream>
#include <tuple>
#include <array>
#include <string_view>
namespace detail {
template <std::size_t N>
constexpr auto split_args(std::string_view s) {
std::array<std::string_view, N> arr{};
std::size_t begin{ 0 }, end{ 0 };
for (std::size_t i = 0; i < N && end != std::string_view::npos; ++i)
{
end = s.find_first_of(',', begin);
arr[i] = s.substr(begin, end - begin);
arr[i].remove_prefix(std::min(arr[i].find_first_not_of(' '), arr[i].size()));
begin = end + 1;
}
return arr;
}
template <std::size_t N, int ...Values, std::size_t ...I>
constexpr auto get_array(std::array<std::string_view, N> strings, std::index_sequence<I...>) {
return std::array<std::pair<std::string_view, int>, N> { std::make_pair(strings[I], Values)... };
}
}
#define EXPAND(x) x
#define VA_ARGS_SIZE(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value
#define F(...) detail::get_array<VA_ARGS_SIZE(__VA_ARGS__), __VA_ARGS__>( detail::split_args<VA_ARGS_SIZE(__VA_ARGS__)>( EXPAND( #__VA_ARGS__ ) ), std::make_index_sequence<VA_ARGS_SIZE(__VA_ARGS__)>{} )
#define A 1
#define B 3
#define C 3
#define D 7
int main()
{
constexpr auto x = F(A, B, C, D);
for (const auto &c : x) {
std::cout << c.first << " " << c.second << "\n";
}
return 0;
}
вывод:
A 1
B 3
C 3
D 7
Спасибо, @rici, за идея!