简体   繁体   中英

Transform a macro parameter name to use as a function in c++

I want to mangle a name passed to a macro to use it as a name of a function. For example I have a macro called foo as below:

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

But I want this macro to be called with parameter like this foo(Bar::do) so I have to change the name to the proper one to use it as a function.

Is there any way to able to implement this? I use c++11 and g++5.x.

Edit:

The problem that I encountered is because of having an old version of a macro, that it could be used with no restriction, so now I have many parts in my code that uses a macro such as foo(Bar::do) , but now I have to generate a function using these names but the function names must be distinctive, so I decided to use macro input parameter as a function name, but I encountered the problem I explained.

This is an example:

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

This is the part of code that I had before, now I want to add a second macro above this part, like this:

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

The both names must be the same, but the FOO2 must generate a function based on the input parameters.

Edit2:

I try here to explain the problem more accurate. Before, I had a macro like this:

#define FOO(name) \
   some codes here

But now I want that have a macro which able to expand as below:

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

Which I can use that like this:

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

And if some_name was in the format of Bar::fcn I want that proper_fcn_name changes that to for example Bar_fcn . In final I wish to have something like this, if some_name was Bar::fcn :

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

I must mention that Bar::fcn is just a name but I have to consider this because my library users used this style before.

I don't think it can be stressed enough that you should not do this and this sounds like there's an XY problem here.

You should probably explain the problem in full, why are you trying to generate this function, how is it used, etc.

Anyway enough preaching, here's a work-around:

#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;
}

If your compiler doesn't have __COUNTER__ you can sort of use __LINE__ most of the time (what is one more ugly hack on top of this pile).

I was interested by your question and made the following example:

#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");
}

In fact it works (it is the output),

The first test

The second test

but I cannot understand what do you want from that strange usage of macro definition - now that looks like automatic copy-paste approach for producing identical functions with different names.

UPDATE

If you really want to use namespace (eg Bar ) consider the following example:

#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");
}

You should understand, that namespace have to be defined, and do is keyword of C++ language (so, you should not use it as function name)

UPDATE 2

If it is possible to change FOO(Bar::do); to FOO(Bar,do); in your old code, you can do simple substitution to generate Bar_do identifiers for call and for definition:

#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 said (in comments to your question):

MYMACRO(A::b) might produce A_b_stub

but unfortunately I do not know how (and suppose that it is impossible) to do replacement of :: with other characters (eg _ ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM