I have a 'system' to generate classes using macros (there is unfortunately no other way).
In some cases, for example for an initializer list, this leads to a trailing comma that I'd like to get rid of:
#define REMOVE_TRAILING_COMMA(...) ?what to put here?
#define FOO a, b, c, d, e, f, g, h,
REMOVE_TRAILING_COMMA(FOO) --> expands to a, b, c, d, e, f, g, h
If it just removes the last argument that would be fine too, of course.
Aka if REMOVE_TRAILING_COMMA(a, b, c)
expands to a, b
.
The macro will always get at least two arguments, so the minimal case
would be: REMOVE_TRAILING_COMMA(a,)
--> expands to a
.
Is this even possible? I searched for a few hours with Google, but nothing comes up.
I would be nice to use #define REMOVE_FIRST(a, ...) __VA_ARGS__
, but that would require reversing macro arguments order. I do not see a way to do it (other then overloading it anyway). So overload the macro on count of arguments and enumerate each overload to remove trailing argument:
// example macro overoad for up to 9 args
// TODO: write REMOVE_TRAILING_COMMA_{1,2,3,4,5....} for each case
#define REMOVE_TRAILING_COMMA_8(_1,_2,_3,_4,_5,_6,_7,_8) \
_1,_2,_3,_4,_5,_6,_7
#define REMOVE_TRAILING_COMMA_9(_1,_2,_3,_4,_5,_6,_7,_8,_9) \
_1,_2,_3,_4,_5,_6,_7,_8
#define REMOVE_TRAILING_COMMA_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) \
REMOVE_TRAILING_COMMA_##N
#define REMOVE_TRAILING_COMMA(...) \
REMOVE_TRAILING_COMMA_N(__VA_ARGS__,9,8,7,6,5,4,3,2,1)(__VA_ARGS__)
#define FOO a, b, c, d, e, f, g, h,
REMOVE_TRAILING_COMMA(FOO) --> expands to a, b, c, d, e, f, g, h
The following was added by Carlo Wood:
Thanks! I wrote a small program to generate the above, so it is easy to increase the maximum number of arguments that this still works with:
#include <string>
#include <iostream>
#include <sstream>
std::string args1_N(int n)
{
std::ostringstream ss;
char const* prefix = "_";
for (int a = 1; a <= n; ++a)
{
ss << prefix << a;
prefix = ",_";
}
return ss.str();
}
int main()
{
int const max_args = 9;
for (int n = 1; n <= max_args + 1; ++n)
std::cout << "#define REMOVE_TRAILING_COMMA_" << n << "(" << args1_N(n) <<
") \\\n " << args1_N(n - 1) << std::endl;
std::cout << "#define REMOVE_TRAILING_COMMA_N(" << args1_N(max_args + 1) << ",N,...) \\\n" <<
" REMOVE_TRAILING_COMMA_##N\n";
std::cout << "#define REMOVE_TRAILING_COMMA(...) \\\n" <<
" REMOVE_TRAILING_COMMA_N(__VA_ARGS__";
for (int a = max_args + 1; a > 0; --a)
std::cout << "," << a;
std::cout << ")(__VA_ARGS__)" << std::endl;
}