c++ - How can I retrieve the last argument of a C99 variadic macro? -
visual studio's error message failed static_assert consists entirely of error code , second parameter static_assert, without additional message indicating static assertion failure. i'd make macro solve problem. example, first try:
#define static_assert(x) static_assert(x, "static assertion failed: " #x)
the first issue run c preprocessor doesn't understand < >
being enclosing delimiters, results in syntax errors templates. following becomes illegal:
template <typename t, typename u> auto safemultiply(t x, u y) -> decltype(x * y) { static_assert(std::is_same<t, u>::value); static_assert(!std::numeric_limits<t>::is_signed); if (x > (std::numeric_limits<decltype(x * y)>::max)()) throw std::overflow_error("multiplication overflow"); return x * y; }
this illegal because comma between t , u in first static_assert
interpreted separating 2 macro parameters, rather template parameters. c preprocessor throws error because static_assert
macro takes 1 parameter.
the 2 main solutions problem use double parentheses and, more recently, use variadic macros:
// invoke macro way... static_assert((std::is_same<t, u>::value)); // ...or define way: #define static_assert(...) static_assert((__va_args__), \ "static assertion failed: " #__va_args__)
the latter solution better, requiring changes macro definition. (the parentheses around __va_args__
in new definition preserve proper order of operations in of weirder cases. may not matter in particular macro, it's habit put parentheses around macros' parameters in macro definitions.)
now if wanted change static_assert
macro take message standard c++ static_assert
, adding prefix message? kind of this, supporting use of std::is_same<t, u>
without use of double parentheses:
// causes syntax error :( #define static_assert(expr, msg) static_assert((expr), \ "static assertion failed: " msg) static_assert(std::is_same<t, u>, "x , y not of same type");
if last parameter of variadic macro, work:
// wish this'd work #define static_assert(..., msg) static_assert((__va_args__), \ "static assertion failed: " msg) static_assert(std::is_same<t, u>, "x , y not of same type");
but since that's not legal, how can legally last parameter of ...
macro parameter set? sure, reverse parameter order, it's not same static_assert
.
there's no easy way last macro argument in general case, can implement version gets last element argument lists predetermined maximum. 64 arguments enough real-world code.
all need count number of arguments passed, , return element n-1
list:
// count arguments #define m_nargs(...) m_nargs_(__va_args__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define m_nargs_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, n, ...) n // utility (concatenation) #define m_conc(a, b) m_conc_(a, b) #define m_conc_(a, b) a##b #define m_get_elem(n, ...) m_conc(m_get_elem_, n)(__va_args__) #define m_get_elem_0(_0, ...) _0 #define m_get_elem_1(_0, _1, ...) _1 #define m_get_elem_2(_0, _1, _2, ...) _2 #define m_get_elem_3(_0, _1, _2, _3, ...) _3 #define m_get_elem_4(_0, _1, _2, _3, _4, ...) _4 #define m_get_elem_5(_0, _1, _2, _3, _4, _5, ...) _5 #define m_get_elem_6(_0, _1, _2, _3, _4, _5, _6, ...) _6 #define m_get_elem_7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7 #define m_get_elem_8(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8 #define m_get_elem_9(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9 #define m_get_elem_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) _10 // last argument - placeholder decrements 1 #define m_get_last(...) m_get_elem(m_nargs(__va_args__), _, __va_args__ ,,,,,,,,,,,)
you can extend large finite amount want few moments' copy , paste.
Comments
Post a Comment