如何通过#define函数将参数添加到格式化的字符串函数调用中

时间:2010-09-08 00:26:17

标签: c++ string string-formatting c-preprocessor

我想创建将参数插入函数调用的宏。例如,我在下面声明了函数Action()。 Action接受一个状态编号的枚举和带有字符串可选参数的格式化字符串。

我想定义宏,这样我就可以调用Action( ActionState1, "someText %d", &arg)而不是使用ActionState1调用State1("someText %d", &arg)作为状态参数。这样宏就会在我的状态参数ActionState1中出现。我正在考虑以下内容:

#define State1(formatedString, ...) Action(ActionState1, formatedString, ...)
#define State2(formatedString, ...) Action(ActionState2, formatedString, ...)
#define State3(formatedString, ...) Action(ActionState3, formatedString, ...)

enum {
  ActionState1,
  ActionState2,
  ActionState3
}

static void Action( State state, String formatedString, ...);

有谁知道这是什么样的格式?

3 个答案:

答案 0 :(得分:2)

使用预处理器无法做到这一点。预处理器允许您对实体进行串联,但不能采用相反的方式。根据您的需要,您需要将State1分解为两个组件State1(后者更重要)并继续进行通话。

然而,更重要的问题是你为什么要这样做?你很难通过这样的转变保存任何打字或获得可读性。

你可以使用模板获取附近的东西:

template <size_t N> 
T State(string fmt, ...) { return Action(N, fmt, ...); } // assume T Action(size_t, ...);

并将上述内容用作:

State<1>(fmtStr, ...);
State<2>(fmtStr2, ...);

但同样,IMO几乎没有语法上的好处。

答案 1 :(得分:2)

我相信__VA_ARGS__正是您所寻找的:

#define State1(formattedString, ...) Action(1, (formattedString), __VA_ARGS__)
 .
 .
 .

这是一个C99功能,Wikipedia claims它们不是任何官方C ++标准的一部分(我注意到这是因为你使用C ++标签),但是一个相当流行的扩展。在this question进行了一些很好的讨论。

答案 2 :(得分:0)

你为什么要创造这样的东西?在C ++中,首先使用流式算子或类似的方法来使用varargs,因为它可以提高类型的安全性。

我不相信有任何方法可以在C ++预处理器宏中执行您想要的操作。如果你有一个va_list版本的Action,你可能会得到类似下面的内容,但我似乎记得...之前的参数必须是POD - 遗憾的是快速搜索无法确认或否认。

#include <cstdarg>
inline void State1(String formatedString, ...)
{
    va_list args;
    va_start(args, formatedString);
    Action(1, formatedString, args);
    va_end(args);
}