rttrorg / rttr Goto Github PK
View Code? Open in Web Editor NEWC++ Reflection Library
Home Page: https://www.rttr.org
License: MIT License
C++ Reflection Library
Home Page: https://www.rttr.org
License: MIT License
First, thanks for the great library! I'm looking for a way to retrieve the value type of a type of an array. For example, given auto type = rttr::type::get<std::vector<int>>()
, how can I get a type for the array values, i.e. int
in this case? Also, how do I create a new instance for the type above and add values to it? type.create()
yields an invalid variant.
Hi.. first of all looks like an awesome lib but i have some problems linking it..
Whichever lib i link from the 7z archive from the download section of your site i get unresolved external symbols.. i use VisualStudio and trying to link the lib to my 3D engine which is an DLL.. have no idea how to fix it and i don't use cmake so could not follow your last step in "Instal" section
And one question i have is will the registered classes be available to my 3D Editor if i link your lib both to the engine and editor as static library and if not how to change that?
Thanks!
As RTTR_ENABLE
is intrusive to the class it cannot be used with third-party types.
An alternative approach I use is to add a .base_class<T>()
member function to the registration interface. This allows a user to manually add base classes to a type when they are not able to - or don't want to - modify a class definition.
namespace thirdparty {
class Foo : public Bar, boost::thingy {};
}
// later
registration::class_<thirdparty::Foo>("Foo")
.base_class<thirdparty::Bar>()
.base_class<boost::thingy>
.constructor<>();
Hello,
I have a class which has a method that returns a std::unique_ptr. It basically constructs an object and gives ownership back to the caller using the std::unique_ptr to transfer ownership.
It uses std::move inside when returning.
The problem is while trying to register this method I get the error:
Error C2338 The given value is not copy constructible, try to add a copy constructor to the class. rttr\detail\variant\variant_impl.h 56
Maybe a new method policy for this might work?
So since i was working with RTTR porting from the old library i came across another issue: STL/STL-like types and serialization of those, my projects uses types reflected in the old library such as std::string and others and my internal STL types such Map, Set, HashMap, and a bit of the EASTL and other templated classes/structs, all of those fields are serialized into JSON/Binary files at the end.
i saw in the issue #30, you're still working an solution for somewhat my problem with the variant_map_view
approach, there's some kind of workaround, without relying with proxy classes, your already implemented wrapper_mapper
may work for templates which has only one parameter...
Thanks you.
Due the lack of support for constexpr
specifier in VS 2013, many functions are not declared with constexpr
. Please add it everywhere where reasonable. Use therefore RTTR_CONSTEXPR
.
I guess this is more a bug + feature request rolled into one.
First, the RTTR equivalent of the following regular C++ code does not work (don't have a working sample right now, but I think you get it):
class Base
{
};
class Derived : public Base
{
};
class Foo
{
Base* mBase;
};
Derived* derived = new Derived();
Foo foo;
foo.mBase = derived; // Assigning pointer-to-derived to pointer-to-base. Works in regular C++, fails in RTTR.
So, we're new'ing a Derived, then assigning that to a pointer-to-base through RTTR.
In addition, the following situation does not work in either C++ or RTTR, but can work in RTTR and is extremely useful for things like object deserialization, so consider this a feature request:
class Base
{
};
class Derived : public Base
{
};
class Foo
{
Derived* mDerived;
};
Base* base= new Derived();
Foo foo;
foo.mDerived = base; // Assigning pointer-to-base to pointer-to-derived. Fails in both C++ and RTTR.
So, we're new'ing a Derived, then assigning that to a pointer-to-base, then trying to assign that to a pointer-to-derived. In C++ this is illegal, because the compiler can't know that Base*
is actually a valid Derived*
instance (so it requires an explicit cast), but in RTTR we can know that this is a valid assignment, since we know the actual type of the instance.
The first bug (not being able to assign pointer-to-derived to pointer-to-base) is caused by the fact that ptr_type<T> argument::is_type()
returns false when faced with this situation. That, in turn, is caused by the implementation to be wrong:
template<typename T>
RTTR_INLINE argument::ptr_type<T> argument::is_type() const RTTR_NOEXCEPT
{
return ((rttr::type::get<T>() == m_type) ||
m_type == type::get<std::nullptr_t>() ||
(m_variant && type::get<variant*>() == type::get<T>()));
}
Specifically it's about the rttr::type::get<T>() == m_type
line. This is a specific type match, which in this situation will return false since the type does not actually match exactly. Instead, the code should check if the types match through a is_derived_from
check, ie:
template<typename T>
RTTR_INLINE argument::ptr_type<T> argument::is_type() const RTTR_NOEXCEPT
{
// T is the type of property we're trying to assign *to*, m_type is the type of argument we're trying to assign *from*
return ((m_type.is_derived_from<T>()) ||
m_type == type::get<std::nullptr_t>() ||
(m_variant && type::get<variant*>() == type::get<T>()));
}
This can be further extended to also implement the 'feature request': by not checking m_type directly, but instead using the most-derived-type of the pointer being assigned, we can also assign pointer-to-base to pointer-to-derived:
template<typename T>
RTTR_INLINE argument::ptr_type<T> argument::is_type() const RTTR_NOEXCEPT
{
// In order to allow assigning a pointer-to-base to a pointer-to-derived (technically illegal in C++, but useful in an RTTI system),
// we need to retrieve the actual type of the pointer we're assigning.
type derived_type = m_type;
if (m_data != nullptr)
{
void* ptr = *reinterpret_cast<void**>(const_cast<void *>(m_data));
if (ptr != nullptr)
derived_type = type::get_derived_type(ptr, m_type);
}
return (derived_type.is_derived_from<T>() ||
m_type == type::get<std::nullptr_t>() ||
(m_variant && type::get<variant*>() == type::get<T>()));
}
Now, while I've tested this code and it works for us, I'm less sure about it because I don't know how it behaves in the presence of multiple base classes. In theory it should work fine, but I don't know enough about multiple base classes to say for sure (I barely ever use them).
hi i would register a unique_ptr is it possible ?
`#pragma once
#include <rttr/registration>
#include <iostream>
#include <memory>
using namespace rttr;
class MyStruct
{
public :
MyStruct();
void func(double);
int data;
std::unique_ptr<int> testUniquePointer;
RTTR_ENABLE()
};
RTTR_REGISTRATION
{
registration::class_<MyStruct>("MyStruct")
.constructor<>()
.property("data", &MyStruct::data)
.method("func", &MyStruct::func)
.property("testWeakPointer", &MyStruct::testUniquePointer);
}`
Add a new property policy called: as_reference_wrapper
or similar.
Which should return the property as inside a std::reference_wrapper
.
The wrapped type can be retrieve later via type::get_wrapped_type()
.
This policy is similar to bind_as_ptr
, however somebody might prefer a solid wrapper, instead of a raw ptr.
Would be possible to show some rttr usage in scripting language context?
IE: Binding to lua or something else.
Thanks
Increase the code coverage to 100%
Check here what code was not yet covered by the unit tests:
So add more unit test to increase it to full 100%
Hi,
Today I was migrating my project to the latest revision of RTTR and came across the following problem. Suppose I have a class that contains a vector of pointers to some object:
struct Container
{
std::vector<int*> data;
};
With the older version of RTTR I was able to register the vector as a readonly property:
RTTR_REGISTRATION
{
using namespace rttr;
registration::class_<Container>("Container")
.property_readonly("data", &Container::data);
}
However, now compilation fails with this ugly error.
Actually, I have traced down the commit that introduced the problem: 7e651ec, however figuring how to fix it is beyond me :) Any ideas?
Due the lack of support for noexcept
specifier in VS 2013, many functions are not declared with noexcept
. Please add it everywhere where reasonable. Use therefore RTTR_NOEXCEPT
.
When comparing two pointer properties, the wrong result will always be returned. To clarify, assuming some two objects with a raw pointer property:
RTTI::Variant valueA = property.get_value(objectA);
RTTI::Variant valueB = property.get_value(objectB);
bool equal = (valueA == valueB); // Always false
The reason for this is that the following specialization of compare_equal
is always selected in the case of raw pointer properties:
template<typename T>
RTTR_INLINE typename std::enable_if<!is_comparable_type<T>::value && !std::is_array<T>::value, bool>::type
compare_equal(const T& lhs, const T& rhs)
{
return compare_types_equal(&lhs, &rhs, type::get<T>());
}
This is the wrong specialization, because it results in comparing the addresses of two pointers, instead of the values of the pointers.
It should select the following specialization instead:
template<typename T>
RTTR_INLINE typename std::enable_if<is_comparable_type<T>::value && !std::is_array<T>::value, bool>::type
compare_equal(const T& lhs, const T& rhs)
{
return (lhs == rhs);
}
This is the correct behaviour. The fix is simple: raw pointers should be included in the list of comparable types, that is, is_comparable_type<T>
should return true when T = T*
.
Can be fixed by simply adding std::is_pointer<T>::value
to the definition of is_comparable_type
, ie:
template<typename T>
using is_comparable_type = std::integral_constant<bool, std::is_same<T, std::string>::value ||
std::is_same<T, string_view>::value ||
std::is_arithmetic<T>::value ||
std::is_enum<T>::value ||
std::is_same<T, std::nullptr_t>::value ||
std::is_pointer<T>::value
>;
Note: this problem also affects the less-than comparison, but the fix to is_comparable_type
also fixes that one.
So I successfully built an xcode project using
cmake -G Xcode
I can see the rttr dylib target / is this for injecting into existing processes?
My steps so far
I create a new target > Terminal App inside the xcode project
I include the rttr_core framework add the rttr as a dependency and run
using namespace rttr;
Normally to resolve this / I'd check to see if the headers are included in the 'framework' - but
it doesn't appear that the rttr is a framwork with public headers / or there's no headers. or I am I missing something.
My bigger task is this > https://reverseengineering.stackexchange.com/questions/11840/recycling-private-framework-sdk-no-header-files-osx
I can point to
using namespace rttr;
// but this runs into lots of errors.
the registration file appears all commented out
Have you considered using virtual box osx simulator?
If anyone gets this working on OSX I'd appreciate any help on steps taken to get up and running.
When a user needs to call a method having it's string name, then this would be called:
for (; itr != m_class_method_list.cend(); ++itr)
{
auto& item = *itr;
if (item.m_class_id != raw_type.get_id())
break;
if (item.m_name_hash != name_hash)
break;
if (std::strcmp(item.m_data->get_name(), name) == 0)
return item.m_data.get();
}
This is slow. Qt does it by generating a switch statement. The overhead could be solved with modern c++1x as well.
Add support for automatic conversion of a wrapped value inside a variant:
Example use case:
int value = 23;
variant var = std::ref(value);
// instead of writing this:
std::cout << var.extract_wrapped_value().to_int() << std::endl;
// user can now write this:
std::cout << var.to_int() << std::endl;
I have used RTTR for a while now and first of all I wanted to renew my gratitude for a great library.
The issue I am facing now concerns template types with multiple template arguments.
For example pairs (e.g. std::pair<std::string, double>) or maps (e.g. std::map<std::string, double>).
Is there a way to implement a "wrapper_mapper" and/or an "array_mapper" to access the wrapped types in these cases?
I know that it is possible to store a function pointer or a lambda in a variant, however a feature that I am missing is the ability to invoke that function dynamically through the variant.
Something like the following:
if (variant.get_type().is_function_pointer()) {
rttr::method method = variant.to_method();
method.invoke();
}
Hello!.
I found your reflection library really interesting and worth to try an shot to my projects, replacing an older reflection library called Reflect by HeliumProject, and already started to port my existent frameworks from Reflect to RTTR but i stepped in this issue: Deferred Type Reflection, i mean register an type (such an class or struct) when i enter into a function.
for example in the older Reflect library did something like this:
template< class ClassT, class BaseT >
void ComponentRegistrar<ClassT, BaseT>::Register()
{
if (...)
{
BaseT::s_ComponentRegistrar.Register();
Reflect::MetaStructRegistrar<ClassT, BaseT>::Register();
}
}
When someone calls this class, this will register the base class and after the actual class, BaseT::s_ComponentRegistrar.Register();
consider that function is the same like void ComponentRegistrar<ClassT, void>::Register()
which register just the class. i wonder if this would work. The old Reflect library keeps an global hashmap of all registered types.
Other question is about RTTR support class hierarchy of two different class inherits the same class hierarchy for exmaple this tree.
|- BaseClass
*- DerivedBaseClass : BaseClass
* DerivedClass : DerivedBaseClass
* DerivedClass2 : DerivedBaseClass
Due to not using exceptions, some kind of logging mechanism would be very nice to get some kind of message when a code path could not be executed successfully. Especially the registration process, or invoke of properties or methods.
Anyone with some ideas or opinions is welcome to shared it here.
I am experimenting with the new associative_container_view, which I find great. Now trying to "map" non-STL types in order to use them with RTTR, but the documentation is still sketchy.
Since no example is provided, I put together one here for Qt's QHash. I think I got pretty close to the "working" implementation, but it still crashes in some cases. I could use some help in debugging this. If found suitable, I would be glad to see it included in the docs.
The patch below solves the problem for me.
diff --git a/src/rttr/detail/type/type_register.cpp b/src/rttr/detail/type/type_register.cpp
index 332fff2..2afc182 100644
--- a/src/rttr/detail/type/type_register.cpp
+++ b/src/rttr/detail/type/type_register.cpp
@@ -440,7 +440,7 @@ void type_register_private::register_custom_name(type& t, string_view custom_nam
auto tmp_type_list = custom_name_to_id.value_data();
for (auto& tt : tmp_type_list)
{
- if (tt.get_raw_array_type() == t)
+ if (tt.get_raw_array_type() == t && tt != t)
{
const auto& orig_name_derived = tt.m_type_data->name;
custom_name_to_id.erase(orig_name_derived);
RTTR 0.9.5 seems to ignore a given CMAKE_INSTALL_PREFIX
command line interface argument:
cmake -G"CodeBlocks - Ninja" -Hrttr-0.9.5-src -Bbuild-rttr-0.9.5/x64/vc140/Release -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_INSTALL_PREFIX=../native/rttr/rttr-0.9.5-x64
cmake --build build-rttr-0.9.5/x64/vc140/Release --config Release --target install
cmake -G"CodeBlocks - Ninja" -Hrttr-0.9.5-src -Bbuild-rttr-0.9.5/x64/mgw63/Release -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_INSTALL_PREFIX=../native/rttr/rttr-0.9.5-x64
cmake --build build-rttr-0.9.5/x64/mgw63/Release --config Release --target install
Both installations are made into the directory ${PROJECT_BINARY_DIR}/install
, instead of the given directory ../native/rttr/rttr-0.9.5-x64
.
Edit: The problem is https://github.com/rttrorg/rttr/blob/master/CMakeLists.txt#L90, where CMAKE_INSTALL_PREFIX
is hardcoded. I think it would be better to follow the standard CMake conventions and do not rely on custom variables.
I found the similar project,the url is https://github.com/AustinBrunkhorst/CPP-Reflection
So ,i think if use it to generator your rttr code,then everythings will gonna to be easy and fast.
We have a custom pointer type that we use to do some registration of objects and such. We'd like to expose properties of this type through RTTR. We've got it mostly working, but we're stuck on actually being able to set the values of these properties. We've defined the wrapper_mapper
(basically identical to the one for unique_ptr
) for our type, so the code looks something like this (simplified):
template<class T>
class ObjectPtr
{
public:
/** Functions for getting, setting, assigning and such **/
private:
T* mPtr;
}
namespace rttr
{
template<typename T>
struct wrapper_mapper<ObjectPtr<T>>
{
using wrapped_type = decltype(std::declval<ObjectPtr<T>>().get());
using type = ObjectPtr<T>;
inline static wrapped_type get(const type& obj)
{
return obj.get();
}
inline static type create(const wrapped_type& value)
{
return ObjectPtr<T>(value);
}
};
}
Now, given the following type of class, we'd like to be able to get/set the pointer value; it should be as transparent as possible to the user that this is actually a pointer wrapper type. Getting the value works, but settings is problematic:
class Foo
{
private:
ObjectPtr<Bar> mPointer;
}
Foo* object = new Foo();
Bar* pointee = object->get_type().get_property("mPointer").get_value(object).extract_wrapped_value(); // Works
object->get_type().get_property("mPointer").set_value(object, ObjectPtr<Bar>(new Bar())); // Works
object->get_type().get_property("mPointer").set_value(object, new Bar()); // Doesn't work
So, it almost works, but we can't set the value of this property from a regular pointer (the last case). This is problematic for us, because during deserialization we want to set the values of these pointers (i.e. pointer fixup, like we do with regular pointers), but we only have naked pointers, so set_value
fails. From our previous discussion in #56, I know that RTTR expects the value type to match exactly, and that we can use variant::convert
to do this:
variant var = b;
auto ret = var.convert(prop.get_type()); // will convert internaly 'Base*' to 'Derived*'
Foo obj;
prop.set_value(obj, var); // will succeed
We're using this code to be able to set raw pointer types in a polymorphic fashion, which is great, but unfortunately the convert code does not deal with this case:
variant var = new Bar();
var.convert(object->get_type().get_property("mPointer").get_value(object).get_type()); // Fails
As an additional curiosity, the wrapper_mapper
expects a create()
function to be defined, which I had hoped would be used for these cases, but as far as I can tell that function is never called and I can't find a place in the codebase where it does. The get
function on wrapper_mapper
is correctly called as expected when getting the value from this proxy object.
Any ideas on how to approach/solve this problem?
Consider the following code:
class Base
{
};
class Derived : public Base
{
};
class SomeOtherClass
{
Derived* mPointerProperty;
};
SomeOtherClass* object = new SomeOtherClass();
object->mPointerProperty = nullptr;
variant value = object->get_type().get_property("mPointerProperty").get_value(object);
Now, suppose we want to retrieve the pointer value from the variant and store it in a base pointer. We can do two things:
Base* pointer_value = value.get_value<Base*>(); // Works because Derived is derived from Base
This works because Derived is derived from Base. Or we can do:
bool converted_ok = false;
Base* pointer_value = value.convert<Base*>(&converted_ok);
This doesn't work; garbage is returned and converted_ok remains false, which is unexpected. The reason for this appears to be that variant::convert
does not correctly deal with inheritance hierarchies when the value is a nullptr; when faced with this case, it goes through variant::try_pointer_conversion
, which calls type::apply_offset
, which returns a nullptr (because ptr
is null), causing the function to fail.
I'm not sure how to fix it this time :)
I'm trying to build this excellent library in the freshly released VS2017, but so far had no luck with that.
Something in type_register.cpp seems off.
Just in case, although it should be reproducable, here's a log
I'm trying to register a class with raw pointer properties (i.e. no smart pointer stuff) and RTTR (0.9.5) does not seem to handle it correctly. The issue seems to be that pointers are being assigned by value. This manifests itself in two different ways:
Both are pretty unexpected, but looking at the code this seems to be by design, which seems pretty odd. I'm building on Windows using VS2015, for x64 bit.
Minimal repro case:
struct Pointee
{
public:
// If you uncomment this line the code will no longer compile. If you leave it commented, the code will compile but crash
//Pointee& operator=(const Pointee&) = delete;
};
struct ClassWithPointer
{
public:
Pointee* mPointee = nullptr;
};
RTTR_REGISTRATION
{
using namespace rttr;
registration::class_<Pointee>("Pointee")
.constructor<>();
registration::class_<ClassWithPointer>("ClassWithPointer")
.constructor<>()(policy::ctor::as_raw_ptr)
.property("mPointee", &ClassWithPointer::mPointee);
}
// Main loop
int main(int argc, char *argv[])
{
rttr::type obj_type = rttr::type::get<ClassWithPointer>();
ClassWithPointer* obj = obj_type.create().get_value<ClassWithPointer*>();
// This line will either crash, or if it doesn't crash, the mPointee member will still be null
obj_type.get_property("mPointee").set_value(*obj, new Pointee());
}
Am I doing something obviously wrong?
I have two enhancement suggestions regarding the variant comparators:
variant::operator>() seems to be missing; while it is perfectly possible to compare the other way around, it would be convenient to have it at one's disposal (along with "<=" and ">=").
I have read in the docs that some types might need the manual registration of the comparators... it would be nice to have the opportunity to check if that happened, so that the program can notice that the result of the comparison is actually invalid: for example by introducing "rttr::type::has_less_than_comparator()" and analogous functions.
Consider the following example:
struct DataStruct
{
float mFloatProperty = 0.0f;
};
class SomeClass
{
public:
std::vector<DataStruct> mArrayOfCompounds;
};
Assuming that DataStruct and SomeClass and their properties are registered in the type system, is there a way to determine/get the nested type
of std::vector<DataStruct>
property using RTTR? For example, in this example, the nested type of the std::vector<DataStruct>
is DataStruct
.
I've found the get_rank_type
functions in variant_array_view
that can do this, but those require an instance of the vector to be able to create the variant_array_view
. While I could create an instance of the vector, it seems needlessly expensive to do that just to determine the type of the array. In addition, creating an instance through RTTR also requires the specific vector specialization to be registered with RTTR in order for a constructor to be present, so it's quite inconvenient.
Is there a better way to determine the type?
(Background information: I'm trying to use this to (recursively) collect a list of all types used by a specific type, so I don't actually have an instance lying around)
EDIT: The above example is for arrays/vectors, but the same goes for associative containers, i.e. std::map and friends; I'd like to retrieve their key and value types as well.
Hi, I'm migrating my project from 0.9.0
to the current master
and can't figure out what is the "right" way to register a pointer type for a class.
Suppose I have class MyClass
. In old times, in the header file I would write:
RTTR_DECLARE_STANDARD_TYPE_VARIANTS(MyClass)
and then in the implementation file:
RTTR_DEFINE_TYPE(MyClass*)
RTTR_REGISTER
{
rttr::class_<MyClass>();
}
This makes sure that both the class and the pointer-to-class are known by RTTR. With the new version, however, we only need:
RTTR_REGISTRATION
{
rttr::registration::class_<MyClass>("MyClass");
}
However, this way MyClass*
is not visible to RTTR.
I found RTTR_REGISTRATION_STANDARD_TYPE_VARIANTS
macro which seems to do what I need, however it's in detail
and is not mentioned in the tutorial or docs (at least I did not see it). So I wonder if this is the "official" way to register pointer types. If not, then what should I use?
Thanks.
To generate the ninja files I used: cmake -G "Ninja"
OS X version: 10.11.2
clang version:
$ clang --version
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.2.0
Thread model: posix
Linker error:
[27/55] Linking CXX shared library bin/librttr_core.0.9.6.dylib
FAILED: : && /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -frtti -std=c++11 -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG -frtti -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -dynamiclib -Wl,-headerpad_max_install_names -o bin/librttr_core.0.9.6.dylib -install_name /Users/mgee/dev/rttr/build/bin/librttr_core.0.9.6.dylib src/rttr/CMakeFiles/rttr_core.dir/constructor.cpp.o src/rttr/CMakeFiles/rttr_core.dir/destructor.cpp.o src/rttr/CMakeFiles/rttr_core.dir/enumeration.cpp.o src/rttr/CMakeFiles/rttr_core.dir/method.cpp.o src/rttr/CMakeFiles/rttr_core.dir/parameter_info.cpp.o src/rttr/CMakeFiles/rttr_core.dir/policy.cpp.o src/rttr/CMakeFiles/rttr_core.dir/property.cpp.o src/rttr/CMakeFiles/rttr_core.dir/registration.cpp.o src/rttr/CMakeFiles/rttr_core.dir/type.cpp.o src/rttr/CMakeFiles/rttr_core.dir/variant.cpp.o src/rttr/CMakeFiles/rttr_core.dir/variant_array_view.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/misc/compare_equal.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/misc/compare_less.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/misc/standard_types.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/conversion/std_conversion_functions.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/constructor/constructor_wrapper_base.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/destructor/destructor_wrapper_base.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/enumeration/enumeration_helper.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/enumeration/enumeration_wrapper_base.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/method/method_wrapper_base.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/parameter_info/parameter_info_wrapper_base.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/property/property_wrapper_base.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/registration/registration_executer.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/type/type_database.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/type/type_register.cpp.o src/rttr/CMakeFiles/rttr_core.dir/detail/variant/variant_compare_less.cpp.o && :
Undefined symbols for architecture x86_64:
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::data() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::size() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::c_str() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::empty() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::length() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::operator[](unsigned long)", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
Temporary workaround to get it to link: Remove the reflection of the std::string functions by deleting these lines.
I am using rttr as a static library in a Visual Studio 2015 solution.
I have two projects:
Project A: Makes calls to a "deserializer" in Project B. This project generates an executable
Project B: This project depends on rttr_core_lib_s_d.lib. Contains classes to be created dynamically by rttr (variant::create()). Every class is registered to rttr in the corresponding .cpp. This project generates a .lib.
I have this code somewhere in project B, that "dynamically" creates an object of a class declared in project B:
rttr::variant arrayVariant = property.get_value(instance); auto arrayItems = arrayVariant.create_array_view(); rttr::type itemType = arrayItems.get_rank_type(1); // itemType = ProjectB::MyClassType. itemType.is_valid() returns true rttr::variant object = itemType.create(); assert(object.is_valid());
This code is working (object.is_valid() == true) in a specific condition:
If Project A has a reference to Project B and both options "Link Library Dependencies" and "Use Library Dependency Inputs" on that reference are set to "True".
However, if I set "Use Library Dependency Inputs" to false, I get "object.is_valid() == false". This only occurs for the creation of objects of classes that are declared in Project B.
For technical reasons relevant to our automated build system, I cannot depend on the flag "Use Library Dependency Inputs" being set to true. Do you have an idea why the creation of objects fails when the option "Link Library Dependencies" is set to false on a project reference?
That option makes the project link against the .obj files instead of the .lib generated.
Thanks!
A very useful feature for reflection systems like RTTR is to be able to attach multiple copies of the same metadata key, each with a different value.
A simplified example taken from some production code in a game engine with a reflection system very similar to RTTR:
REFLECT(FooNode)
(
// used by node graph UI to enumerate the events an instance of FooNode can emit
node::event<EventA>(),
node::event<EventB>(),
node::event<EventC>()
)
.method("something", &type::something)
.property("thing", &type::thing);
Notably that interface doesn't even require an explicitly-named metadata key and instead just keys metadata by the type of the metadata itself. However, an interface that still requires the user to specify keys but allowed multiple values would be good on its own. Key-less metadata is not explicitly required, though it can be a further convenience (perhaps by just using the type
of the value as the key if no key is explicitly specified?).
All wrappers (property
, method
, constructor
, destructor
& enumeration
) currently hold a pointer to the wrapper base class.
When the client holds a valid item, the pointer is set, otherwise its a nullptr
.
Every invoke of a member method for the wrappers mentioned above, checks for nullptr.
That's an unnecessary check, just provide for the invalid case a derived class,
which handles this case. All if checks could be removed.
To get the idea:
Current implementation:
variant method::invoke(instance object) const
{
if (is_valid())
return m_wrapper->invoke(object);
else
return variant();
}
New implementation:
variant method::invoke(instance object) const
{
return m_wrapper->invoke(object);
}
m_wrapper
would point to the a derived class which implement the invalid case.
Hello,
Is it possible to assign metadata (like we can do for properties) to a type?
I would like to do something like this:
registration::class_("MyClass").metadata(UserFriendlyName, "My Class");
Thanks
I have noticed that conversion of enum's to their raw type with convert() does not work. This surprised me, since it is the same procedure I use for other (non-enum) types. I prepared here a short example test.
Note however, that it is still possible to extract the type with get_value(), so I wanted to ask if this is by design (and why it is so only for enum's).
It seems to be necessary to retrieve the used binding of registered items at runtime.
Use case was: the policy: bind_as_ptr
was used, in order to avoid copying the whole property when retrieving it. In order to avoid copying the whole data, when setting the property back, the user needs to know whether the property has used this kind of policy.
Therefore all items, should expose its used policy via an enum at runtime.
I have a question. If i have some classes with reflection in my app. Then load a .dll with other classes with reflection. Will the ones loaded from a dll be available for me? Or can i somehow introduce their reflection data to my app?
I am a new (since yesterday) user of the library, and first of all I wanted to tank you for such an useful tool.
I am starting now to explore the API and running some tests.
It seems that registration of a class requires a copy-constructor, even if rttr::policy::ctor::as_raw_ptr
is used.
Small example attached.
test.zip
This fails to build with a static assert.
Am I missing something?
Thank you in advance!
Hi,
I was trying to compile rttr version 0.95 on MacOS 10.12.3. I followed the instruction from here, and did the following
cd rttc-0.95
mkdir build; cd build
cmake -DCMAKE_BUILD_TYPE=Release ../
make
It proceeds until 39%
:
Scanning dependencies of target rttr_core
[ 1%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/constructor.cpp.o
[ 2%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/destructor.cpp.o
[ 4%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/enumeration.cpp.o
[ 5%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/method.cpp.o
[ 7%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/parameter_info.cpp.o
[ 8%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/policy.cpp.o
[ 10%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/property.cpp.o
[ 11%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/registration.cpp.o
[ 13%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/type.cpp.o
[ 14%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/variant.cpp.o
[ 16%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/variant_array_view.cpp.o
[ 17%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/misc/compare_equal.cpp.o
[ 19%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/misc/compare_less.cpp.o
[ 20%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/misc/standard_types.cpp.o
[ 22%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/conversion/std_conversion_functions.cpp.o
[ 23%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/constructor/constructor_wrapper_base.cpp.o
[ 25%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/destructor/destructor_wrapper_base.cpp.o
[ 26%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/enumeration/enumeration_helper.cpp.o
[ 27%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/enumeration/enumeration_wrapper_base.cpp.o
[ 29%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/method/method_wrapper_base.cpp.o
[ 30%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/parameter_info/parameter_info_wrapper_base.cpp.o
[ 32%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/property/property_wrapper_base.cpp.o
[ 33%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/registration/registration_executer.cpp.o
[ 35%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/type/type_database.cpp.o
[ 36%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/type/type_register.cpp.o
[ 38%] Building CXX object src/rttr/CMakeFiles/rttr_core.dir/detail/variant/variant_compare_less.cpp.o
[ 39%] Linking CXX shared library ../../bin/librttr_core.dylib
Undefined symbols for architecture x86_64:
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::data() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::size() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::c_str() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::empty() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::length() const", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::operator[](unsigned long)", referenced from:
__GLOBAL__sub_I_standard_types.cpp in standard_types.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [bin/librttr_core.0.9.5.dylib] Error 1
make[1]: *** [src/rttr/CMakeFiles/rttr_core.dir/all] Error 2
make: *** [all] Error 2
Any idea? Thanks.
P.S. I am using:
cmake version 3.7.1
C compiler AppleClang 8.0.0.8000042
C++ compiler AppleClang 8.0.0.8000042
Hi,
First of all, great library! I have some questions about it.
I have classes with members like this:
class User
{
public:
boost::optional<string> m_name;
boost::optional<Mailbox> m_mailbox;
boost::optional<vector<string>> m_notes;
}
I have declared those members as properties of the class and I can access them correctly.
I have two problems:
1- During the looping over the properties of User
, how can I know which one is a boost::optional (without using type name, which is not portable)?
My solution for now is to add metadata manually to each boost::optional property to indicate this, but I have a feeling this might not be the best solution.
2- Before getting the underlying value of the boost::optional property, I need to call is_initialized() on the property(which is of type boost::optional) to make sure the value is valid (otherwise, it's undefined behavior). The problem is that in order to call that method, I need to have an instance of boost::optional which I can't because Type is not known until runtime.
Unless I do a ton of ifs for each type(in this case, one for string, one for Mailbox and one for vector), I don't see how I can call is_initialized() for all types without typing them in the source code like this:
rttr::instance u = User();
for(const auto& property : object.get_properties())
{
if(!property.get_metadata(IsOptionalKey).to_bool())
continue;
const auto& type = property.get_metadata(UnderlyingOptionalTypeKey);
const rttr::type& underlyingOptionalType = type.get_value<rttr::type>();
if(underlyingOptionalType == rttr::type::get<string>())
{
const boost::optional<string>& val = property.get_value(u).get_value<boost::optional<string>>();
if(val.is_initialized()) { /* ... */ }
}
else if(underlyingOptionalType == rttr::type::get<Mailbox>())
{
const boost::optional<Mailbox>& val = property.get_value(u).get_value<boost::optional<Mailbox>>();
if(val.is_initialized()) { /* ... */ }
}
}
Is there something I'm missing or there is no easy solution to this?
Similar to the variant_associative_view class, add a new class called variant_sequential_view
.
The variant_array_view class should be marked as deprecated.
The advantage of the new class will be:
At the moment it is not possible to use a rttr::variant object a property for a class and set the value via rttr::property::set_value.
This should be fixed.
In rttr/src/rttr/detail/variant_associative_view/variant_associative_view_creator_impl.h, variant_associative_view_p.h is included but it is not installed by make install.
To reproduce:
#include <rttr/type>
int main()
{
}
LANG=C g++ test.cpp -I install/include -L install/lib -l rttr_core
In file included from install/include/rttr/detail/variant_associative_view/variant_associative_view_creator.h:63:0,
from install/include/rttr/detail/variant/variant_data_policy.h:35,
from install/include/rttr/detail/variant/variant_impl.h:36,
from install/include/rttr/variant.h:950,
from install/include/rttr/detail/type/get_create_variant_func.h:32,
from install/include/rttr/detail/type/type_impl.h:36,
from install/include/rttr/type.h:1080,
from install/include/rttr/type:31,
from test.cpp:1:
install/include/rttr/detail/variant_associative_view/variant_associative_view_creator_impl.h:31:77: fatal error: rttr/detail/variant_associative_view/variant_associative_view_p.h: No such file or directory
#include "rttr/detail/variant_associative_view/variant_associative_view_p.h"
RTTR functions like get_properties
currently return a std::vector
object. Creation of this object requires allocating backing memory every single time that get_properties
is invoked.
A superior approach would be to return a "range" type like an array_view
instead of the vector
in such interfaces. This type would still allow using C++ iteration and range-based-for over the returned elements, but would remove the use of allocation.
An array_view
may be too simple to use for some of the data structures used in RTTR's internals, of course, but an iterator_range
can also be written that operates on a custom iterator type that is able to properly introspect RTTR's data.
Using such range types judiciously removes all need to ever allocate temporary containers while querying or enumerating the type database with very little (if any) loss of features currently present in RTTR.
// range for array-like containers
template <class T>
struct array_view {
T* _begin = nullptr;
T* _end = nullptr;
array_view() = default;
array_view(T* being, T* end) : _begin(begin), _end(end) {}
T* begin() const { return _begin; }
T* end() cont { return _end; }
size_t size() const { return _end - _begin; }
T& operator[](size_t i) const { return _begin[i]; }
};
// implementation of a range getter
array_view<property> type::get_properties() const
{
// rough simulacrum of RTTR internals
return {m_class_properties.data(), m_class_properties.data() + m_class_properties.size()};
}
// usage of the library doesn't change at all
for (property& p : my_type.get_properties())
{ /*...*/ }
Please, check example. Are there any errors?
auto value = make_shared<int>(25);
variant var = value;
cout << var.extract_wrapped_value().to_string() << endl; // Don't print anything
// Working example
int t = 25;
auto value1 = ref(t);
variant var1 = value1;
cout << var1.extract_wrapped_value().to_string() << endl; // Print 25
printing the name of following type:
std::cout << type::get<std::reference_wrapper<std::string>>().get_name() << std::endl;
Results in following output with MSVC 2015:
class std::reference_wrapper<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >
Desired output:
class std::reference_wrapper< std::string >
Every type with which has the original type name included should be replaced with the custom registered name. That are normally templates, but function ptrs should also be honored...
Coding starting point:
type_register.cpp
std::string type_register_private::derive_name(const type_data& wrapper_type, const type_data& array_raw_type, string_view name)
Hi, sorry, it's me again :) I was wondering if RTTR supports std::unique_ptr
member properties. From the documentation of wrapper_mapper
I conclude that they are supported. However, when I try to register a member field of type std::unique_ptr
, I get the following compilation error, which seems to originate in the fact that unique pointers are not copy-constructible. So what is the status actually?
#include <rttr/registration>
struct A
{
std::unique_ptr<int> p;
};
RTTR_REGISTRATION
{
using namespace rttr;
registration::class_<A>("A")
.property_readonly("p", &A::p);
}
Compiler: GCC 5.4 and Clang 3.8.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.