How to Make a Variadic MACro for Std::Cout

How to easily create fully variadic functions with C++ 98 standard?

A template can't have zero template parameters. The syntax that starts with template <> instead is used for an explicit specialization: a declaration to be used instead of the template for a specific set of template arguments.

So your zero-argument version will need to skip the template <> part. You might do something like:

#define TINYFORMAT_TEMPLATE_HEAD_0(...)
#define TINYFORMAT_TEMPLATE_HEAD_1(...) template < TINYFORMAT_ARGTYPES_1(__VA_ARGS__) >
#define TINYFORMAT_TEMPLATE_HEAD_2(...) template < TINYFORAMT_ARGTYPES_2(__VA_ARGS__) >
#define TINYFORMAT_TEMPLATE_HEAD_3(...) template < TINYFORMAT_ARGTYPES_3(__VA_ARGS__) >

#define TINYFORMAT_TEMPLATE_HEAD(n, ...) TINYFORMAT_TEMPLATE_HEAD_ ## n (__VA_ARGS__)

#define FACTORY(n,...) \
TINYFORMAT_TEMPLATE_HEAD(n,__VA_ARGS__) \
inline void some(TINYFORMAT_VARARGS(n,__VA_ARGS__)) \
{ \
fprintf(stderr, "variadic" TINYFORMAT_PASSARGS(n,,) ); \
}

Make variadic macro / method which prints all variables names and values

You can do this with a bit of a hack. The hack is not very robust, but it should be acceptable if you're using it for debugging purposes.

The idea is to stringify the entire variadic macro argument, and then take the sequence of labels apart by tokenising on commas. That requires that none of the variadic arguments include a comma, which will be the case if they are all variable names, but there is no way to require that and in fact the proposed code below will happily accept expressions, as shown.

#define SHOW(...) show(std::cout, #__VA_ARGS__, __VA_ARGS__)

template<typename H1>
std::ostream& show(std::ostream& out, const char* label, H1&& value) {
return out << label << "=" << std::forward<H1>(value) << '\n';
}

template<typename H1, typename ...T>
std::ostream& show(std::ostream& out, const char* label, H1&& value, T&&... rest) {
const char* pcomma = strchr(label, ',');
return show(out.write(label, pcomma - label) << "="
<< std::forward<H1>(value)
<< ',',
pcomma + 1,
std::forward<T>(rest)...);
}

(live on coliru)

For simplicity, and to avoid std::string, I've used the standard C strchr function rather than C++ library functions. Apologies to anyone that is offended.

Variadic macro for checking if variable equals one of variadic arguments

You might want to use C++17 fold expression:

template<class... Args>
bool check(const unsigned int var, const Args&... args)
{
return ((var == args) || ...);
}

Then you can invoke something like this:

check(var, CONSTANT_1, CONSTANT_2, CONSTANT_3);

Modern / generic approach to variadic macro with stringizing

Apparently there's a library that does exactly what you want! Here's a full example:

#include <iostream>
#include <nlohmann/json.hpp>
#include <visit_struct/visit_struct.hpp>

struct MyStruct {
int propertyA;
std::string propertyB;
std::vector<int> propertyC;
};

VISITABLE_STRUCT(MyStruct, propertyA, propertyB, propertyC);

using nlohmann::json;

template <typename T>
std::enable_if_t<visit_struct::traits::is_visitable<std::decay_t<T>>::value>
from_json(const json &j, T &obj) {
visit_struct::for_each(obj, [&](const char *name, auto &value) {
// json_get(value, name, j);
j.at(name).get_to(value);
});
}

int main() {
json j = json::parse(R"(
{
"propertyA": 42,
"propertyB": "foo",
"propertyC": [7]
}
)");
MyStruct s = j.get<MyStruct>();
std::cout << "PropertyA: " << s.propertyA << '\n';
std::cout << "PropertyB: " << s.propertyB << '\n';
std::cout << "PropertyC: " << s.propertyC[0] << '\n';
}

C++ variadic macro for pairs

CREATE_CLASS(Person, (const char*, name), (int, age), (float, height))

This is going to be the easier option to work with, since the preprocessor syntax handles balanced parentheses, in a way so that e.g. (const char*, name) is a single argument to the macro despite containing a comma.

So one straightforward solution would be to provide wrapper macros which accept an argument of the form (type, varname), and pass its elements to your actual two-argument macros:

#define DECL_VAR(type,var)\
type _##var;
#define DECL_VAR_PAIR(pair)\
DECL_VAR pair
#define DECL_GETSET(type,var)\
type get_##var() const {return _##var;}\
void set_##var(type val) {_##var = val;}
#define DECL_GETSET_PAIR(pair)\
DECL_GETSET pair

#define CREATE_CLASS(C, ...)\
class C {\
private:\
MAP(DECL_VAR_PAIR, __VA_ARGS__)\
public:\
MAP(DECL_GETSET_PAIR, __VA_ARGS__)\
};

CREATE_CLASS(Person, (const char*, name), (int, age), (float, height))

So for example, when the expansion of MAP(DECL_VAR_PAIR, __VA_ARGS__) in the last CREATE_CLASS line passes the one argument (int, age) to DECL_VAR_PAIR, steps of the expansion include:

DECL_VAR_PAIR((int, age))
DECL_VAR(int, age) // since DECL_VAR_PAIR(x) is just DECL_VAR then x
int _##age;
int _age;

Though if you have a bunch of things you want to do with the paired arguments, creating all those wrapper macros could get cumbersome. Instead, we can add a MAP-like macro that expects its arguments to be lists enclosed in parentheses. First, notice that in <map.h>, the steps which actually apply a macro to one of the arguments are closely related to the main MAP macro:

#define MAP0(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP1)(f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP0)(f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL(MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))

If the argument x is already parentheses around one list of arguments to pass to the macro f, we just want parallel versions to skip adding the parentheses around x:

#define MAP_TUPLES0(f, x, peek, ...) f x MAP_NEXT(peek, MAP_TUPLES1)(f, peek, __VA_ARGS__)
#define MAP_TUPLES1(f, x, peek, ...) f x MAP_NEXT(peek, MAP_TUPLES0)(f, peek, __VA_ARGS__)
#define MAP_TUPLES(f, ...) EVAL(MAP_TUPLES1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))

I called this MAP_TUPLES rather than MAP_PAIRS because it's not actually limited to pairs. It can pass argument lists of any size to any macro, as long as the number of macro parameters matches. You could even use a variadic macro with argument lists of varying sizes.

A use of this MAP_TUPLES to get your CREATE_CLASS, assuming your original DECL_VAR and DECL_GETSET, looks like:

#define CREATE_CLASS(C, ...)\
class C {\
private:\
MAP_TUPLES(DECL_VAR, __VA_ARGS__)\
public:\
MAP_TUPLES(DECL_GETSET, __VA_ARGS__)\
};

CREATE_CLASS(Person, (const char*, name), (int, age), (float, height))

See the full example at coliru.

How to sum variadic arguments passed in to a variadic macro?

Don't use a variadic macro. Visual C++ 14 (or 2015) is a C++11/14 compliant compiler. That means it it supports variadic templates. You can easily recurse a parameter pack to get the sum of the parameters and getting the count can be done by using sizeof.... This lets you write count as

template<typename... Args>
auto count(Args&&...)
{
return sizeof...(Args);
}

and then sum can be written as

// base case
template<typename T>
auto sum(T&& first)
{
return first;
}

// multiple parameters case
template<typename T, typename... Args>
auto sum(T&& first, Args&&... rest)
{
return first + sum(rest...);
}

using those in

int main()
{
std::cout << count(3,4,5) << "\n";
std::cout << sum(3,4,5);
}

prints

3
12

which you can see in this live example.


As suggested by HolyBlackCat you can use the dummy array trick to avoid using recursion. That would give you a sum that looks like

template <typename ...P> 
auto sum(const P &... params)
{
using dummy_array = int[];
std::common_type_t<P...> ret{}; // common_type_t is to find the appropriate type all of the parameter can be added to
(void)dummy_array{(void(ret += params), 0)..., 0}; // add the parameter to ret, discard it's result, return the value of 0 for the array element
return ret;
}

Do note though that this might not work correctly for all types, like shown here with std::valarray. Changing it to

template <typename T, typename ...P> 
auto sum(T first, P&&... rest) // copy the first parameter to use it as the accumulator
{
using dummy_array = int[];
(void)dummy_array{(void(first += params), 0)..., 0}; // add the parameter to ret, discard it's result, return the value of 0 for the array element
return first;
}

should be more correct, although it could probably be improved some more (suggestions/edits welcomed)


If you can use a C++17 complaint compiler then sum can be even further simplified using a fold expression like

template<typename... Args>
auto sum(Args&&... rest)
{
return (rest + ...);
}

How to get name for each argument in variadic macros?

If you can use Boost.Preprocessor, you can do this:

#define PROCESS_ONE_ELEMENT(r, unused, idx, elem) \
BOOST_PP_COMMA_IF(idx) BOOST_PP_STRINGIZE(elem) , " " , elem

#define PRINT_ALL(...) \
print_all(BOOST_PP_SEQ_FOR_EACH_I(PROCESS_ONE_ELEMENT, %%, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))

[Live example]

I use %% as a placholder for "unused value."

Count number of variadic arguments in macro function

_1 to _10 are just placeholders from the start in order to make sure N is positioned over the correct number from 10 to 0 (depending on __VA_ARGS__). They serve no purpose other than occupying a position.

Since each macro parameter must have a distinct identifier, those identifiers are as good as any.


Regarding your edit, that is limitation of the preprocessor. An empty token sequence is a valid argument to a macro. So it really is a single argument, because __VA_ARGS__ , (note the comma) becomes such an argument.

It's quite a known issue, so much so that C++20 added the __VA_OPT__ preprocessor macro. It allows to add the comma conditionally. On C++20, the implementation can be fixed to work as expected like this:

#define CV_VA_NUM_ARGS(...)      CV_VA_NUM_ARGS_HELPER(__VA_ARGS__ __VA_OPT__(,) 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

Is there a portable way to implement variadic CHECK and PROBE macros for detecting the number of macro arguments in C++?

After some more digging I found this answer from the VS Developer Community, which provides the solution: an extra layer of indirection and some funky rebracketing. Rewriting to match the original question:

#define CHECK_N(x, n, ...) n
#define CHECK_IMPL(tuple) CHECK_N tuple //note no brackets here
#define CHECK(...) CHECK_IMPL((__VA_ARGS__, 0)) //note the double brackets here
#define PROBE(x) x, 1

godbolt demonstrates that this works across MSVC, gcc, and clang. Some of the other macro tools from the original link also require some adjustments (eg IIF(x)) but again, more layers of indirection seem to solve those too.

I hope one day to be able to use the compiler option /Zc:preprocessor as was mentioned elsewhere, which also fixes these macros, unfortunately that breaks certain other libraries (such as the Windows SDK).



Related Topics



Leave a reply



Submit