0

I'm trying to make a macro to help construction of a class like this one :

class MyClass
{ 
    std::string name;
    float* valPtr;

public:
    MyClass(std::string _name, float* _valPtr = nullptr)
}

I would like to create an instance of MyClass like

float f = 0.0f;
MYCLASS(f); //calls MyClass _f("f", &f);

So I have made the macro :#define MYCLASS(x) MyClass _##x(#x, &x)

The problem is that I also would like to use it to reference float from other class :

class OtherClass
{
public:
    float val;
    OtherClass(float _val) : val{ _val } {}
}

//___________________________________________

int main()
{
    OtherClass a(2.0f);
    MYCLASS(a.val); // I would like it to call MyClass _val("val", &a.val)
}

I'm stuck on this, thank you for any help ☺

e.farman
  • 335
  • 2
  • 12
  • 1
    AFAIK you can't split a token at a dot. Better split for it yourself. – user202729 Mar 28 '18 at 09:36
  • 1
    Use `MYCLASS(a, val)` – llllllllll Mar 28 '18 at 09:43
  • While it's slightly wasteful to split at runtime, there's no easy `constexpr` solution yet. But I suspect you don't need `.name` that often anyway. Postpone the split until needed; store a `const char* name_cstr;` and make `std::string name() const` a function. – MSalters Mar 28 '18 at 14:50

1 Answers1

0

It looks like creating macro that generate exactly "MyClass _val("val", &a.val)" from nested member will be very hard to implement without compromise. For clarity, let's split problem into 3 simple issues, and try to solve them one by one:

MYCLASS(a.val); // Should generate "MyClass _val("val", &a.val);"
                                              |    |      |
                                      issue  (3)  (2)    (1)

Issue (1):

This part will be handled without any problem by already shown implementation #define MYCLASS(x) MyClass _##x(#x, &x).

Issue (2):

float member in the other class might be also a pointer. Then string after -> should be taken into consideration. May also happen that object that contain float is member of other object (nested) e.g:

struct Foo1
{
    struct Foo2
    {
        Foo1* foo1;
    };

    Foo1* foo1;
    Foo2 foo2;
};

MYCLASS(Foo1::foo1->foo2.foo1); // "foo1" is expected in (2)

so to get "foo1" from very nested float for (2) use nameof macro implemented by @Dmitry Bravikov

Issue (3):

Here trouble comes. There is Foo1::foo1->foo2.foo1 and we would like to convert it to (3) by adding underscore _. If Foo1::foo1->foo2.foo1 will be just predicted by _ code will not compile (variable name can not contain ., ::, nor ->). If not allowed characters will be removed (by normal method or constexpr), such sanitized string (string, std::string, char*, std::array<>) will have to be returned.

Problem is that in C++ there is no way to convert any kind of (string, std::string, char*, std::array<>) to variable name. See Convert string to variable name or variable type. Case is not hopeless because you can use use some hard coded string, but then when you will not be able to use MYCLASS() macro twice in the same scope. You can think about implementation that solves this problem, but probably then you will lose transparency during debugging...

Summary:

I would advise creating two arguments macro MYCLASS(name, val); (already pointed by @liliscent) as probably the most effective solution for your problem

atrelinski
  • 432
  • 2
  • 9