Skip to content

Commit a75ff4f

Browse files
authored
Merge pull request #34 from ReflectCxx/release-2.0.readMe
Updated readme.md
2 parents 904150d + 09a0f34 commit a75ff4f

File tree

1 file changed

+115
-111
lines changed

1 file changed

+115
-111
lines changed

README.md

Lines changed: 115 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
# Reflection Template Library C++
2-
###### (in development...)
3-
Reflection Template Library for Modern C++
4-
- Introspect a (user defined) class/struct/type, modify objects at run time without dealing with its type at "Compile Time".
5-
- **Static Library**, core design is to maintain several tables of function/variable pointers, collected at compile time and providing a mechanism to access them in complete absence of their types at run time.
6-
## Exclusive Features,
7-
- Pure **Builder Pattern** for manual registration of types, super-easy to understand, No use of any "Mysterious MACROS" at all.</br>Thats Right- **NO MACROS!!**
8-
- No need to add any bit of a code to any class/struct/type (to be reflected) declaration or to its implementation.</br>Yes, **No Code Littering, Keep it clean!**
9-
- Manage all the manual registration of any required type in one single implementation unit, away from rest of the code in project.</br>Or in a **Class with Single Responsibility!**
10-
- Create an Object of **"CxxMirror"**, pass all type information to reflect as constructor parameter and you're good to GO!
2+
3+
The **Reflection Template Library for C++** enables introspection of user-defined types, allowing modification of objects at runtime without needing to know their actual types at compile time.
4+
5+
Static library, the core design maintains several tables of function pointers(registered by the user) wrapped in lambdas and providing a mechanism to access at runtime.
6+
7+
## Key Features
8+
9+
- **Builder Pattern**: Manual registration of types is simple and intuitive, with no mysterious macros involved.
10+
- **Clean Code**: No reflection-related code needs to be added to class, struct, or function declarations or implementations— keeping your codebase clean and free of clutter.
11+
- **Centralized Registration**: Manage all manual registrations in a single implementation unit, separate from the rest of your project code.
12+
- **Simple Integration**: Just create an instance of `CxxMirror`, pass all type information to reflect as a constructor parameter, and you’re done!
1113
```c++
12-
const rtl::CxxMirror myReflection({/*.. Pass all type information ..*/});
14+
rtl::CxxMirror cxxReflection({/*.. Pass all type information ..*/});
1315
```
14-
- Wrap that powerful object in a singleton and use C++ Reflection with similar features as in Java or C#.
15-
- *To generate this boilerplate code automatically, can be used **clang-reflect**
16-
https://github.com/neeraj31285/clang-reflect
17-
which is under development right now. Once completed, this boilerplate code can be generated automatically for any large projects.*
16+
The *cxxReflection* object provides interface to query and instantiate registered types.
17+
- **Thread-Safe & Exception-Safe**: The library is designed to be thread-safe and exception-safe, providing error codes on possible failures to ensure robust operation.
18+
- **Automatic Code Generation**: To generate manual registration code automatically, `clang-reflect` can be used. It is a work-in-progress tool available here: *https://github.com/ReflectCxx/clang-reflect*. This tool will generate registration code for any large project without requiring changes to your project’s code.
1819
1920
## How To build (Windows/Linux),
2021
@@ -30,129 +31,132 @@ to build, any IDE applicable to the generator can be used or you can also just b
3031
```sh
3132
cmake --build .
3233
```
33-
Run **CxxReflectionTests** binary, generated in ../bin folder. *(currently tested on windows and Ubuntu-20 only)*
34+
Run **CxxReflectionTests** binary, generated in ../bin folder. *(tested on windows and Ubuntu-20)*
3435
## How To Use,
35-
- Class to reflect - **Person.h** *(Independent of any code related to reflection)*
36+
In this example, we'll reflect a simple Person class. `Person.h`,
3637
```c++
37-
#pragma once
38-
#include <string>
39-
40-
class Person
41-
{
38+
class Person {
4239
int age;
4340
std::string name;
41+
4442
public:
45-
Person() :name("NULLSTR"), age(-1) {}
46-
Person(std::string pName, int pAge) : name(pName), age(pAge) {}
43+
Person();
44+
Person(std::string, int);
4745

48-
int getAge() { return age; }
49-
void setAge(int pAge) { age = pAge; }
50-
std::string getName() { return name; }
51-
void setName(std::string pName) { name = pName; }
46+
void setAge(int);
47+
void setName(std::string);
48+
49+
int getAge() const;
50+
std::string getName() const;
5251
};
5352
```
54-
- Do manual registration while creating **CxxMirror** object. *(..somwhere in some far far away .cpp file..)*
53+
### Step 1: Register the Class with 'CxxMirror'
54+
Manually register the class and its members when creating a **`CxxMirror`** object.
5555
```c++
56-
57-
#include "CxxMirrorBuilder.h" //Provides interface to RTL
58-
59-
//User defined types, to be reflected.
60-
#include "Person.h"
56+
#include "CxxMirrorBuilder.h" // Provides registration interface.
57+
#include "Person.h" // User-defined types to be reflected.
6158
6259
using namespace rtl;
6360
6461
const CxxMirror& MyReflection()
6562
{
66-
static const CxxMirror cxxMirror(
67-
{
68-
//Function registration
69-
Reflect().record("Person").function("setAge").build(&Person::setAge),
70-
Reflect().record("Person").function("getAge").build(&Person::getAge),
71-
Reflect().record("Person").function("setName").build(&Person::setName),
72-
Reflect().record("Person").function("getName").build(&Person::getName),
63+
static const CxxMirror cxxMirror({
64+
// Register member functions
65+
Reflect().record<Person>("Person").method("setAge").build(&Person::setAge),
66+
Reflect().record<Person>("Person").method("getAge").build(&Person::getAge),
67+
Reflect().record<Person>("Person").method("setName").build(&Person::setName),
68+
Reflect().record<Person>("Person").method("getName").build(&Person::getName),
7369
74-
//Constructor registration
75-
Reflect().record("Person").constructor<Person>().build(), //ctor taking zero arguments
76-
Reflect().record("Person").constructor<Person>().build<string, int>() //ctor with arguments, Person(string, int)
70+
// Register constructors
71+
Reflect().record<Person>("Person").constructor<Person>().build(), // Default constructor
72+
Reflect().record<Person>("Person").constructor<Person>().build<std::string, int>() // Constructor with parameters
7773
});
74+
7875
return cxxMirror;
7976
}
8077
```
81-
Registration syntax is simple **Builder Pattern**,
78+
Registration syntax,
8279
```c++
83-
84-
Reflect().nameSpace("..") //use if type is enclosed in a namespace, pass namespace as string.
85-
.record("..") //pass class/struct name as string.
86-
.function("..") //pass function name as string.
87-
.build(*); //pass function pointer.
88-
89-
Reflect().nameSpace("..")
90-
.record("..")
91-
.constructor<..>() //pass struct/class type as template parameter.
92-
.build<..>(); //zero args for constructors, register constructor signature as template params.
80+
Reflect().nameSpace("..") // Optional: specify namespace if the type is enclosed in one.
81+
.record<..>("..") // Register class/struct type (template parameter) and its name (string).
82+
.method("..") // Register function by name.
83+
.build(*); // Pass function pointer.
84+
85+
Reflect().nameSpace("..")
86+
.record<..>("..")
87+
.constructor<..>() // Register constructor with template parameters as signature.
88+
.build<..>(); // No function pointer needed for constructors.
9389
```
94-
- In main.cpp, Use **Person** class via Reflection without exposing the **Person Type**.
95-
(*New underlying access-mechanism is in progress. These will not work currenty but final design will stay the same as below.*)
90+
### Step 2: Use the 'Person' Class via Reflection
91+
In main.cpp, use the **`Person`** class without directly exposing its type.
9692
```c++
97-
#include <iostream>
98-
#include "CxxMirror.h"
99-
100-
using namespace std;
93+
#include "RTLibInterface.h" // Single header including reflection access interface.
10194
extern const rtl::CxxMirror& MyReflection();
10295
103-
int main()
96+
int main()
10497
{
98+
// Get 'class Person', Returns 'Record' object associated with 'class Person'
99+
std::optional<Record> classPerson = MyReflection().getClass("Person");
100+
101+
/* Create an instance of 'class Person' via reflection using the default constructor.
102+
Returns 'RStatus' and 'Instance' objects.
103+
*/ auto [status, personObj] = classPerson->instance();
104+
105105
```
106-
Get Class & Method objects from reflection as **ReflClass** & **ReflMethod**,
107-
```c++
108-
auto classPerson = MyReflection().getClass("Person"); //(returns instance of ReflClass)
109-
auto getAge = classPerson.getMethod("getAge"); //(returns instance of ReflMethod)
110-
auto getName = classPerson.getMethod("getName");
111-
auto setAge = classPerson.getMethod("setAge");
112-
auto setName = classPerson.getMethod("setName");
113-
```
114-
Create Instance using default constructor *(the one registered as **ctor::VOID**)*,
115-
```c++
116-
//returns instance of Person wrapped in ReflObject<> which extends std::unique_ptr<>
117-
auto personObj1 = classPerson.instance();
118-
```
119-
Method Call Syntax : **ReflMethod(ReflObject<>).invoke<RETURN_TYPE>()**,
120-
```c++
121-
int age = getAge(personObj1).invoke<int>();
122-
string name = getName(personObj1).invoke<string>();
123-
cout << "Person : { name : " << name << ", age: " << age << " }"; //Outs- Person : { name : NULLSTR, age: -1 }
124-
```
125-
No need to specify RETURN_TYPE if its void,
126-
```c++
127-
setAge(personObj1).invoke(23);
128-
setName(personObj1).invoke(string("Scott"));
129-
age = getAge(personObj1).invoke<int>();
130-
name = getName(personObj1).invoke<string>();
131-
cout << "Person : { name : " << name << ", age: " << age << " }"; //Outs- Person : { name : Scott, age: 23 }
132-
```
133-
Create instance using overloaded constructor *(the one registered as **ctorArgs<string, int>**)*,
106+
- `RStatus` provides an error code `(rtl::Error)` that indicates the success or failure of the reflection call, and it also contains the return value (if any) wrapped in `std::any`.
107+
- `Instance` holds the created object (with its type erased), managed on the heap using `std::shared_ptr`.
134108
```c++
135-
auto personObj2 = classPerson.instance(string("John Doe"), 37);
136-
age = getAge(personObj2).invoke<int>();
137-
name = getName(personObj2).invoke<string>();
138-
cout << "Person : { name : " << name << ", age: " << age << " }"; //Outs- Person : { name : John Doe, age: 37 }
109+
110+
/* Create an instance via reflection using a parameterized constructor.
111+
Argument types/order must match else call will fail, returning error-code in 'status'.
112+
*/ auto [status, personObj] = classPerson->instance(std::string("John Doe"), int(42));
113+
114+
// Get method of 'class Person'. Returns a callable 'Method' object.
115+
std::optional<Method> setAge = classPerson->getMethod("setAge");
116+
117+
// Call methods on the 'Person' object. returns 'RStatus'.
118+
RStatus rst = setAge->on(personObj).call(int(42));
119+
// or with different syntax,
120+
RStatus rst = (*setAge)(personObj)(int(42));
121+
122+
// Get method of 'class Person' that returns a value.
123+
std::optional<Method> getName = classPerson->getMethod("getName");
124+
125+
// Call method, returns 'RStatus' containing return value.
126+
RStatus retName = getName->on(personObj).call();
127+
// or with different syntax,
128+
RStatus retName = (*getName)(personObj)();
129+
130+
// Extract the return value.
131+
std::string nameStr = std::any_cast<std::string>(retName.getReturn());
139132
}
140133
```
141-
## Reflection Features,
142-
- Create instances & call methods in complete absence of its type.
143-
- Supports default & copy constructor along with all kinds of overloads.
144-
- Supports all kinds of member function overloading, including constant function overloads(WIP) for *const objects*.
145-
- Supports single, multiple, multilevel & virtual inheritance (WIP).
146-
- Query a class for its super classes & for all its derived classes (vice-versa) (WIP).
147-
- Resolves *Inheritance- Diamond Problem* (WIP).
148-
- Supports *virtual methods - Overriding*.
149-
- No need of any 3rd party dependencies.
150-
- Manual registration with **NO MACROS**.
151-
152-
## TODO,
153-
- Unit test cases (WIP)
154-
- Class/Struct's Field reflection (Currently only methods are supported).
155-
- Enum Class reflection.
156-
- Exception handling (WIP)
157-
- Access specifiers for reflection *(presently any Method/Field registerd is considered as public)*
158-
- Light weight JSON Serialization/Deserialization feature.
134+
- `std::any_cast` will throw an exception if correct type is not specified.
135+
- Check, `CxxTypeRegistration/src/MyReflection.cpp` for all sort of type registrations.
136+
- Check, `CxxReflectionTests/src` for test cases.
137+
138+
## Reflection Features
139+
- ✅ Register and invoke functions, supporting all overloads.
140+
- ✅ Register classes/structs and reflect their methods, constructors, and destructors.
141+
- ✅ Invoke the default constructor.
142+
- ✅ Invoke the copy constructor with a non-const reference argument.
143+
- ✅ Invoke the copy constructor with a const reference argument.
144+
- ✅ Invoke any overloaded constructor.
145+
- ✅ Invoke non-const member functions.
146+
- ✅ Invoke const member functions.
147+
- ✅ Invoke static member functions.
148+
- ✅ Automatically invokes destructor for objects created on the heap via reflection.
149+
- ❌ Reflect properties of classes/structs, providing getter/setter methods.
150+
- ❌ Invoke functions with perfect forwarding.
151+
- ❌ Reflect enums.
152+
- ❌ Reflect classes with composite types that are also reflected.
153+
- ❌ Support single, multiple, multilevel, and virtual inheritance.
154+
155+
## License
156+
This project is licensed under the MIT License. See the LICENSE file for more details.
157+
158+
## Contributions
159+
Contributions are welcome! If you find a bug, have a feature request, or want to contribute to the project, feel free to open an issue or submit a pull request on GitHub.
160+
161+
## Contact
162+
For any questions, suggestions, or feedback, you can reach out via GitHub or email at `neeraj.singh31285@outlook.com`.

0 commit comments

Comments
 (0)