Skip to content

Latest commit

 

History

History
217 lines (166 loc) · 5.94 KB

tutorial_metarepo.md

File metadata and controls

217 lines (166 loc) · 5.94 KB

Tutorial for using MetaRepo and runtime meta data

MetaRepo is used to register and retrieve meta types at running time. The registered meta types can be any C++ types, no matter if they are declared with DeclareMetaType or not.

Include headers

Header for MetaRepo

#include "metapp/metarepo.h"

To use the built-in meta types, we must include "metapp/allmetatypes.h"

#include "metapp/allmetatypes.h"

Define some C++ variables and types to reflect for

Global variable

std::vector<std::string> textList { "hello", "world" };

Global getter/setter

int value_ = 0;
void setValue(const int newValue)
{
  value_ = newValue;
}

int getValue()
{
  return value_;
}

Global function

std::string concat(const int a, const bool b, const std::string & c)
{
  return std::to_string(a)
    + (b ? "true" : "false")
    + c
  ;
}

Global class

class MyClass
{
};

Define the global variable metaRepo, we will register all global meta data there.

metapp::MetaRepo metaRepo;

Register meta data

To get meta data from MetaRepo, we must register meta data first.

Register an accessible. An accessible is any meta type that implements meta interface MetaAccessible.
The second argument in registerAccessible is a metapp::Variant. Any data can be casted to metapp::Variant implicitly, so we don't need to specify metapp::Variant explicitly.

  metaRepo.registerAccessible("textList", &textList);
  metaRepo.registerAccessible("value", metapp::createAccessor<int>(&getValue, &setValue));

Register an callable. A callable is any meta type that implements meta interface MetaCallable.
A callable can be a pointer to function, pointer to member function, or std::function, and so on.

  metaRepo.registerCallable("concat", &concat);

Register a C++ type, here is class MyClass.
This is only to demonstrate how to use registered meta type. There is a separate completed tutorial for how to use MetaClass.

  metaRepo.registerType("MyClass", metapp::getMetaType<MyClass>());

Register a nested MetaRepo, we can use it to simulate namespace.

  metapp::MetaRepo nestedRepo;
  nestedRepo.registerVariable("one", 1);
  // For best efficiency, we move the `nestedRepo` into `metaRepo` to avoid copying.
  // `nestedRepo` can also be std::shared_ptr, or std::unique_ptr.
  // `nestedRepo` can also be raw pointer or reference to MetaRepo, in such case, the caller must ensure 
  // `nestedRepo` lives as long as `metaRepo`, otherwise `metaRepo` will hold dangling pointer.
  metaRepo.registerRepo("myNamespace", std::move(nestedRepo));

Use field meta data

Get the meta data of field "value"

metapp::MetaItem fieldValue = metaRepo.getAccessible("value");

Call metapp::accessibleGet to get the value of the field. The first parameter is the Variant.
Call getTarget() to get the underlying Variant.

ASSERT(metapp::accessibleGet(fieldValue.asAccessible(), nullptr).get<int>() == 0);

getTarget() can also be omitted, the MetaItem can convert to Variant automatically

ASSERT(metapp::accessibleGet(fieldValue, nullptr).get<int>() == 0);

Now let's set a new value

metapp::accessibleSet(fieldValue, nullptr, 5);
ASSERT(getValue() == 5);
ASSERT(metapp::accessibleGet(fieldValue, nullptr).get<int>() == 5);

Now append some new texts to textList

metapp::MetaItem fieldtextList = metaRepo.getAccessible("textList");
metapp::accessibleGet(fieldtextList, nullptr).get<std::vector<std::string> &>().push_back("good");
ASSERT(metapp::accessibleGet(fieldtextList, nullptr).get<const std::vector<std::string> &>()[0] == "hello");
ASSERT(metapp::accessibleGet(fieldtextList, nullptr).get<const std::vector<std::string> &>()[1] == "world");
ASSERT(metapp::accessibleGet(fieldtextList, nullptr).get<const std::vector<std::string> &>()[2] == "good");

Use function meta data

Get the meta data of method "concat".

metapp::MetaItem methodConcat = metaRepo.getCallable("concat");

Call metapp::callableInvoke to invoke the method, and pass the arguments.
The return value is a metapp::Variant.

metapp::Variant result = metapp::callableInvoke(methodConcat, nullptr, 38, true, "Great");
ASSERT(result.get<const std::string &>() == "38trueGreat");

Use registered types

  metapp::MetaItem myClassType = metaRepo.getType("MyClass");
  ASSERT(myClassType.asMetaType() == metapp::getMetaType<MyClass>());

Use registered nested repo

  const auto repoItem = metaRepo.getRepo("myNamespace");
  const metapp::MetaRepo * nestedRepo = repoItem.asMetaRepo();
  const auto one = nestedRepo->getVariable("one");
  ASSERT(one.asVariable().get<int>() == 1);

Use MetaItemView

  // Get all registered accessible as MetaItemView
  const metapp::MetaItemView itemView = metaRepo.getAccessibleView();
  // We registered two accessibles
  ASSERT(itemView.size() == 2);
  // The first accessible is textList
  const metapp::MetaItem & firstItem = itemView[0];
  ASSERT(firstItem.getName() == "textList");
  // The second is value
  ASSERT(itemView[1].getName() == "value");

  // We can also use range based for loop
  std::string allNames = "";
  for(const metapp::MetaItem & item : itemView) {
    allNames += item.getName();
  }
  ASSERT(allNames == "textListvalue");