I know that #define
is not really good to use, I am not sure if that's a duplicate but I couldn't find what's the best way is to do this:
I have a program that uses a definition like:
#define True GetObject(true)
I need to replace the define statement with actual code
but I can't think of a way to make it so the following code:
int main() {
auto c = True;
return 0;
}
turns into this at compile time:
int main() {
auto c = GetObject(true);
return 0;
}
Summary: I want an exact replacement of "define" as code, I found something like an inline function could help, but is there a way to make an inline variable?
I tried the following but ended up with an error
inline Object True = GetObject(true);
NOTE: I can't make Object/GetObject a constexpr class
NOTE 2: I'd like to avoid turning True
to True()
if that's possible
This is basically a question for educational purposes but I would like to use it in a small library I am writing, If you could tell me what would be the best way to do this I'd be really happy
Thanks!!!
EDIT 1
As the first above is not quite clear, I'd like True to call GetObject(true)
function every time
The returned value is going to be the same but the function call is necessary
EDIT 2
I didn't think it is necessary to explain this but, the library I am creating is a simple layer (that's not really important for this),
The macro name True
is completely random, it could be named something completely different (I am just using it for testing)
The macro is used to create a Class that I need to use a lot in my code and I also need it to create a new instance of the class (not just a copy)
I also need to update the class a lot so to add more constants in the constructor I would need to have some simple way to do, I don't think it would be good to go in each of my 10 headers/sources and replace every instance
with the values that represent 'True' and other states.
the part about removing () is because I don't think it's convenient to see a lot of parenthesis in something that looks like a variable (or maybe some kind of compile-time constant?)
The following is probably similar in principle to your code.
It is solved with #define
and sets a serialno
to each Object
and prints something out to the console:
#define True GetObject(true)
#define False GetObject(false)
#include <iostream>
using namespace std;
class Object {
public:
Object(bool b, int serial) : _b(b), _serialno(serial) {};
bool _b;
int _serialno;
};
Object GetObject(bool b) {
static int curserial = 0;
Object result(b, ++curserial);
cout << "Created Object with serialno " << result._serialno << " and value " << boolalpha << result._b << endl;
return result;
}
int main() {
auto c = True;
auto d = True;
auto e = False;
return 0;
}
which generates the output
Created Object with serialno 1 and value true
Created Object with serialno 2 and value true
Created Object with serialno 3 and value false
Now we change it to the same result without '#define':
#include <iostream>
using namespace std;
class Object;
void GotObject(Object& o);
class Object {
public:
Object(bool b) : _b(b), _serialno(++curserial) {};
Object(const Object& other) : _b(other._b), _serialno(++curserial) {
GotObject(*this);
};
bool _b;
int _serialno;
inline static int curserial = 0;
};
void GotObject(Object& o) {
cout << "Created Object with serialno " << o._serialno << " and value " << boolalpha << o._b << endl;
}
inline Object True(true);
inline Object False(false);
int main() {
auto c = True;
auto d = True;
auto e = False;
return 0;
}
Output:
Created Object with serialno 3 and value true
Created Object with serialno 4 and value true
Created Object with serialno 5 and value false
Each time we assign the values of True
or False
to new variables the copy constructor is called and can do, whatever you did in GetObject
.
Small variant: If we choose this alternative custom constructor instead of the one in the code,
Object(bool b) : _b(b), _serialno(0) {};
we would get as output:
Created Object with serialno 1 and value true
Created Object with serialno 2 and value true
Created Object with serialno 3 and value false
The difference is, whether the serialno
is also counted up for True
and False
themselves or only after assigning those to a variable.
For Generating True
and False
the first constructor is called, for the following assignments to other variables, the second constructor.
You could also keep a bool _original
variable inside Object
to only call GetObject()
, which states whether you copy from the original True
or False
. It is true only for True
and False
. You can recognize those by them calling a special constructor. If you want to make it safe to use, you can make that constructor private, so it can only be called by friend functions or by static factory methods.
In the following code, GotObject is not called from assigning from c
to f
.
#include <iostream>
using namespace std;
class Object;
void GotObject(Object& o);
class Object {
public:
Object(bool b) : _b(b), _serialno(0), _original(true) {};
Object(const Object& other) : _b(other._b), _original(false), _serialno(0) {
if (other._original)
GotObject(*this);
};
bool _original;
bool _b;
int _serialno;
};
void GotObject(Object& o) {
static int curserial = 0;
o._serialno = ++curserial;
cout << "Created Object with serialno " << o._serialno << " and value " << boolalpha << o._b << endl;
}
inline Object True(true);
inline Object False(false);
int main() {
auto c = True;
auto d = True;
auto e = False;
auto f = c;
return 0;
}
Output:
Created Object with serialno 1 and value true
Created Object with serialno 2 and value true
Created Object with serialno 3 and value false