【问题标题】:Transform a macro parameter name to use as a function in c++转换宏参数名称以用作 C++ 中的函数
【发布时间】:2016-08-02 04:49:49
【问题描述】:

我想修改传递给宏的名称以将其用作函数的名称。例如,我有一个名为 foo 的宏,如下所示:

#define foo(name) void name(const string& in) { \\do something }

但我希望使用像 foo(Bar::do) 这样的参数调用此宏,因此我必须将名称更改为正确的名称才能将其用作函数。

有什么方法可以实现吗?我使用 c++11 和 g++5.x。

编辑:

我遇到的问题是因为有一个旧版本的宏,它可以不受限制地使用,所以现在我的代码中有很多部分使用了诸如foo(Bar::do)之类的宏,但现在我必须使用这些名称生成函数但函数名称必须有区别,所以我决定使用宏输入参数作为函数名称,但遇到了我解释的问题。

这是一个例子:

void Bar::do(some_parameters)
{
   FOO(Bar::do);
}

这是我之前的代码部分,现在我想在这部分上方添加第二个宏,如下所示:

FOO2(Bar::do)
void Bar::do(some_parameters)
{
  FOO(Bar::do);
}

两个名称必须相同,但FOO2必须根据输入参数生成函数。

编辑2:

我在这里尝试更准确地解释问题。 之前,我有一个这样的宏:

#define FOO(name) \
   some codes here

但现在我想要一个可以扩展如下的宏:

#define FOO2(name) void proper_fcn_name(name)(const string &name){ do the same thing here}
#define FOO(name) proper_fcn_name(name)(#name)

我可以这样使用:

FOO2(some_name)
void Bar::fcn()
{
  FOO(some_name); 
}

如果some_name 的格式为Bar::fcn,我希望proper_fcn_name 将其更改为例如Bar_fcn。最后我希望有这样的东西,如果some_nameBar::fcn

void Bar_fcn(const stirng& name) { }
void Bar::fcn()
{
  Bar_fcn("Bar::fcn");
}

我必须提到Bar::fcn 只是一个名称,但我必须考虑这一点,因为我的图书馆用户以前使用过这种风格。

【问题讨论】:

  • 为什么要使用宏,而不是 std::function
  • 看来你要使用宏定义而不是方法模板
  • 您要解决的更大问题是什么?你为什么要这样做(不管这是什么)?
  • 我相信他是在说他想要一个给定输入 namespace::member(其中命名空间可能是命名空间或类)的宏,它将能够输出一个有效的、唯一的函数名。例如。 MYMACRO(A::b) 可能会产生 A_b_stub,但我不明白它是否还必须应对 MYMACRO(x)MYMACRO(ns::cls::mbr)
  • 所以更准确地说这不是'mangling',它只是在前面加上一个命名空间?

标签: c++ c++11 macros c-preprocessor


【解决方案1】:

我对您的问题很感兴趣,并做了以下示例:

#include <iostream>
#include <string>
using namespace std;
#define foo(name) void name (const string& in) { cout << in << endl; }

// function with name bar_do
foo(bar_do)

// function with name bar_do
foo(do_bar)

int main(void)
{
    bar_do("The first test");
    do_bar("The second test");
}

事实上它可以工作(它是输出),

第一次测试

第二次测试

但我不明白你想从宏定义的奇怪用法中得到什么 - 现在这看起来像是自动复制粘贴方法来生成具有不同名称的相同函数。

更新

如果您真的想使用命名空间(例如Bar),请考虑以下示例:

#include <iostream>
#include <string>
using namespace std;
#define foo(name) void name (const string& in) { cout << in << endl; }

namespace Bar{
    void func(const string& in);
}

foo(Bar::func)

int main(void)
{
    Bar::func("The special test");
}

你应该明白,命名空间必须被定义,而do是C++语言的关键字(所以,你不应该使用它作为函数名)

更新 2

如果可以将旧代码中的FOO(Bar::do); 更改为FOO(Bar,do);,您可以进行简单的替换以生成Bar_do 标识符用于调用和定义:

#include <iostream>
#include <string>
using namespace std;

#define defgen(class_name,method_name) void class_name##_##method_name(const string& in) {  cout << in << endl; }
#define callgen(class_name,method_name,...) class_name##_##method_name(__VA_ARGS__);

// produses definition
defgen(Bar,do)

int main(void)
{
    // produces call with particular value as an argument
    callgen(Bar,do,"The call test");
}

kfsone 说(在 cmets 中对您的问题):

MYMACRO(A::b) 可能会产生 A_b_stub

但不幸的是,我不知道如何(并且假设不可能)将:: 替换为其他字符(例如_)。

【讨论】:

  • @VolAd 请考虑我添加到帖子中的编辑说明。
  • 我在我的编辑注释中添加了一个sn-p代码,这可能会更清楚地显示问题。 Bar::do 对我来说没有任何意义,其他一些开发人员将其用于他们想要的目的,我不确定 Bar 是命名空间还是类,我只想更改开发人员的名称从此宏请求一个可用作函数名的名称。
  • “我不确定Bar 是命名空间还是类” 这不是支持宏的论据。这只是意味着您需要努力创建和使用正确的命名约定。例如我将this_thing 用于命名空间,将ThisThing 用于类。实际上,这是反对宏的另一个论点,因为阅读您的宏代码的人(包括您未来的自己)很快就会说“我不确定foo 是什么或bar_do 是在哪里声明的/定义'。只需使用母语功能。只有在您有令人信服的理由时才应使用宏,而 IMO 这确实不是。
  • 我觉得这里有一个误解,我只想写宏,我不是使用宏的人,一般宏可以接受任何名称,但目前使用的是一个我在问题中提到的约定。
【解决方案2】:

我认为你不应该这样做的压力太大了,这听起来像这里有一个 XY 问题。

你可能应该完整地解释这个问题,你为什么要尝试生成这个函数,它是如何使用的等等。

不管怎样讲道,这里有一个变通方法:

#include <iostream>
#include <map>
#include <string>
#include <functional>

std::map<std::string, std::function<void(const std::string&)>> g_functions;

#define FOO(name) static void* nonsense##__COUNTER__ =                \
                  (void*)&(  g_functions[ #name ] =                   \
                   [](const std::string& in)                          \ 
                  {                                                   \
                    std::cout << "generated function for : " << #name \ 
                              << " called with arg:" << in << std::endl; \ 
                  });
#define FOO2(name) {g_functions[ #name ](#name); }

namespace Bar
{
    FOO(Bar::func)
    void func()
    {
        FOO2(Bar::func);
    }

}

int main() {
    Bar::func();
    return 0;
}

如果您的编译器没有__COUNTER__,您可以在大多数情况下使用__LINE__(还有什么更丑陋的hack)。

【讨论】:

  • 请看我帖子的Edit2注释。我试图更清楚地解释问题,我认为你的建议不符合我解决问题的要求/
  • @MohsenTamiz 好吧,我确实按照您的意愿生成了一个函数,只是没有给它命名。通过使用 lambda,我让编译器生成名称。我的解决方案只是在地图查找和次要 std::function 调用效率低下方面有一些明显的开销。但除此之外,我看不出我没有满足您的要求。
  • 是的,现在我明白了,但我认为 lambda 函数内的 #name 必须更改为 in。您的解决方案可以解决问题,但是正如您提到的那样,该解决方案有一些明显的开销,我认为我必须考虑这一点,如果我没有其他解决方案,那么您的解决方案可能是我现在能做的最好的事情。但首先我必须寻找其他开销较小的可能解决方案。
猜你喜欢
  • 2015-08-05
  • 2022-12-18
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多