[我正在研究的项目中有一个记录表达式的宏。我的任务是添加以下功能:将多个值传递到其中,并单独打印每个图像。我设法通过1到5个参数使此工作相对容易。仍然可以很好地传递到函数中。
我现在遇到的问题是初始化程序列表不再起作用。该项目使用可变参数作为内部数组的初始化对象,例如func(std::vector<int>{0, 1, 0, 1})
。自从我实现了multi arg之后,由于逗号的原因,它不再起作用。
我知道我可以执行func((std::vector<int>{0, 1, 0, 1}))
,这会很好,但是我知道这不会因工作而受到欢迎。有没有一种方法可以使我的产品在没有多余括号的情况下工作,或者在需要时添加额外的括号?
以下是一些相关片段:
// Intermediate macro "chooser"
#define func_x(x, A, B, C, D, E, Func, ...) Func
// Macro to be called and used by user
// First param must be blank to allow for 0 argument function
#define func(...) func_x(, ##__VA_ARGS__, \
func_5(__VA_ARGS__), func_4(__VA_ARGS__), func_3(__VA_ARGS__), \
func_2(__VA_ARGS__), func_1(__VA_ARGS__), func_0())
// Macros for 1 through 5 args, calls the func_VA macro.
#define func_1(A1) func_VA(A1)
#define func_2(A1, A2) func_1(A1), func_VA(A2)
#define func_3(A1, A2, A3) func_2(A1, A2), func_VA(A3)
#define func_4(A1, A2, A3, A4) func_3(A1, A2, A3), func_VA(A4)
#define func_5(A1, A2, A3, A4, A5) func_4(A1, A2, A3, A4), func_VA(A5)
// Prints expression and type
// We use a variadic macro to support commas inside expressions (e.g.
// initializer lists):
#define func_VA(...) \
func_macro::DebugOutput(__FILE__, __LINE__, __func__, #__VA_ARGS__) \
.print(func_macro::type_name<decltype(__VA_ARGS__)>(), (__VA_ARGS__))
func(std::vector<int>{0, 1, 0, 1});
// Errors
func((std::vector<int>{0, 1, 0, 1}));
// Works, but also prints the () when logging so not ideal. Better than nothing though.
我一直在尝试在宏的某些部分加上方括号,以尝试解决此问题,但无济于事。像#define func_1(A1) func_VA((A1))
或类似名称。
编辑:我已经取得了一些进展
您可以假设,如果我叫func_1
,则像#define func_1(...) func_VA(__VA_ARGS__)
一样声明func_1(std::vector<int>{0, 1, 0, 1});
也可以。
我制作了一个返回(__VA_ARGS__)
的“包装器”宏,尽管该字符串版本确实带有多余的括号,但它允许该宏与列表init一起正常使用。尽管我无法通过某种方式使您(作为用户)不必在数组上调用包装器(这比将braccets放置在自己的位置上更难)。
如果可以将DebugOutput::print
更改为可变参数模板,则可以执行以下操作:
#define func(...) \
func_macro::DebugOutput{__FILE__, __LINE__, __func__, #__VA_ARGS__} \
.print(__VA_ARGS__)
namespace func_macro
{
struct DebugOutput
{
const char* filename = nullptr;
int line = 0;
const char* funcname = nullptr;
const char* argsString = nullptr;
template <typename ... Ts>
void print(const Ts&... args) const
{
std::cout << filename << ":" << line << " in " << funcname << std::endl;
std::cout << "func(" << argsString << ")\n";
((std::cout << typeid(args).name() << ": " << args << std::endl), ...);
}
};
}