【问题标题】:C/C++ macro expanding to argument, argument as stringC/C++ 宏扩展为参数,参数为字符串
【发布时间】:2012-01-25 17:25:46
【问题描述】:

我有许多变量与工程规范文档中的元素命名相同,因此名称的字符串版本也很有用。

我发现自己经常使用这样的宏:

#define MACRO(a) a, #a

典型用法是:

void someFunction(int a, const char *name);

someFunction(MACRO(meaningfully_named_variable));

我的问题有三个:

  • 有更好的方法吗?
  • Boost 或其他库中是否有类似的宏?
  • 如果不是,我该如何改进和重命名它以使其清晰有用?

编辑 我应该说上面是一个最小的例子。函数可能有其他参数,命名实体可能是数据成员,甚至可能是函数本身。

我正在考虑的另一个 C++ 扩展是一个类 NamedRef,它可以接收宏的内容。

template <typename T>
struct NamedRef
{
    NamedRef(T *t, const char *name) : t(t), name(name) { }
    T *t;
    const char *name;
};

template <typename T>
NamedRef<T> namedRef(T &t, const char *name)
{
    return NamedRef<T>(&t, name);
}

#define WITH_NAME(a) a, #a

// more sophisticated usage example
void otherFunction(double, NamedRef<int>, bool);

otherFunction(0.0, namedRef(object.WITH_NAME(meaningful_member_name)), false);

【问题讨论】:

  • 我要做的就是为宏选择一个更具描述性的名称,例如WITH_NAME().
  • 按照@MarkRansom 的建议去做。我的回答是“没关系”,而且 Boost 有一个名为 BOOST_STRINGIZE(X) 的宏。

标签: c++ c-preprocessor stringification


【解决方案1】:

你可以更进一步:

#define SOMEFUNCTION(a) somefunction(a, #a)

但是,这仅在您多次调用相同的函数时才有用。否则,我认为没有比您的示例更好的方法了。当然,您应该将宏的名称更改为更有意义的名称,例如 ARGUMENTS 或其他名称。

【讨论】:

  • 是的,但是如果我有很多接收var, name的函数,那么我将不得不编写很多宏。
  • 不一定 => #define MACRO(funct_ptr, var) funct_ptr(var, #var) 所以你需要这么多宏,你有多少不同的函数参数签名......
  • 好的,想法不错,但我认为如果可能的话保留函数语法会更清楚,函数也可能有其他参数。
【解决方案2】:

您可能会发现XMACROs 对于此类工作很有用。

【讨论】:

    【解决方案3】:
    #define someFunction(a)  if (1) stringized_someFunction((a), #a ); else (void)0
    void stringized_someFunction(int a, const char* name);
    

    if (1) 东西包裹了宏,这样它就不会(通常)与循环、分支、if 语句等混淆。

    然后你会像这样调用你的函数:

    int r = 4;
    someFunction(r);
    

    您实际上只为每个“函数声明”添加了一行。如果 C 预处理器允许多个步骤,您可以将它们全部打包成一个,但可惜它不允许。

    我忘记了,因为我希望很明显你需要编写你的函数:

    void stringized_someFunction(int a, const char* name)
    {
      // Do stuff here
    }
    

    无论如何,这样阅读应该会更容易、更漂亮。

    【讨论】:

    • 您之前忘记了宏定义中的分号。另外,我认为在这种情况下不需要将其包装在 if(1) 中。
    • 我知道您need to wrap multi-statement macros 是为了防止他们破坏代码,但我不明白单个语句的原因,如果您能提供一个反例,将不胜感激。
    • if (1) 如果被包装的函数需要返回一个值,会导致问题。
    • 在if(1) 或do{}while(0); 中包装函数调用没有意义,因为您无法捕获函数调用的结果。
    【解决方案4】:

    正如杰西回答的那样,

    你可以这样写:

    void function1(int a, const char* name)
    {
        cout << "a: " << a << endl;
        cout << "name: " << name << endl;
    }
    
    void function2(double d, const char* name, const char *str)
    {
        cout << "d: " << d << endl;
        cout << "name: " << name << endl;
        cout << "str: " << str << endl;
    }
    
    #define MACRO(functionName, a) functionName(a, #a)
    #define MACRO2(functionName, a, ...) functionName(a, #a, __VA_ARGS__)
    
    int main()
    {
        int a = 10;
        MACRO(function1, a);
        double d = 10.5;
        MACRO2(function2, d, "Hello world");
        return 0;
    }
    

    如果您要传递更多参数,则可以使用使用可变参数的 MACRO2。您必须相应地传递函数名称。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多