// Using Gorgon's Reflection system to handle member assignments.
namespace internal {
template<class T_, int Ind>
// Sets the member by name if the name exists in the structure's reflection.
void SetByName_setif(T_ &obj, const std::string &name, const std::string &value) {
if(T_::Reflection().Names[Ind] == name)
obj.*(T_::ReflectionType::template Member<Ind>::MemberPointer()) = Gorgon::String::To<typename T_::ReflectionType::template Member<Ind>::Type>(value);
}
// Since we can't travel template members in run time, we use Gorgon Sequence for to do that using template parameters.
template<class T_, int ...S_>
void SetByName_expand(Gorgon::TMP::Sequence<S_...>, T_ &obj, const std::string &name, const std::string &value) {
(SetByName_setif<T_, S_>(obj, name, value), ...);
}
}
// Caller for the above.
template<class T_>
void SetByName(T_ &obj, const std::string &name, const std::string &value) {
internal::SetByName_expand(typename Gorgon::TMP::Generate<T_::ReflectionType::MemberCount>::Type{}, obj, name, value);
}
template<class T_, int Ind>
auto GetByName_getif(const T_& obj, const char* name) -> T_::ReflectionType::template Member<Ind>::Type {
if (T_::Reflection().Names[Ind] == name) {
return obj.*(T_::ReflectionType::template Member<Ind>::MemberPointer());
}
return {};
}
template <class T_, int ...S_>
auto GetByName_expand(Gorgon::TMP::Sequence<S_...>, const T_& obj, const char * name) {
return (GetByName_getif<T_, S_>(obj, name), ...);
}
template <class T_>
auto GetByName_(const T_& obj, const char * name) {
return GetByName_expand(typename Gorgon::TMP::Generate<T_::ReflectionType::MemberCount>::Type{}, obj, name);
}
std::any
'den yararlanıp şöyle bir şey yazdım;class Get {
private:
std::any value;
template<class T_, int Ind>
void ByName_getif(const T_& obj, const std::string& name) {
value.reset();
if (T_::Reflection().Names[Ind] == name)
value = obj.*(T_::ReflectionType::template Member<Ind>::MemberPointer());
}
template <class T_, int ...S_>
void ByName_expand(Gorgon::TMP::Sequence<S_...>, const T_& obj, const std::string& name) {
(ByName_getif<T_, S_>(obj, name), ...);
}
public:
template <class T_>
std::any ByName(const T_& obj, const std::string& name) {
ByName_expand(typename Gorgon::TMP::Generate<T_::ReflectionType::MemberCount>::Type{}, obj, name);
return value;
}
template <class T_>
std::any operator()(const T_& obj, const std::string& name) {
return ByName(obj, name);
}
};
Get GetByName;
void *value = NULL;
Hala casting gerektiriyor. Casting'i elemem lazım. Pointerlara girersem daha da karışacak ortalık, template meta-programming yeterince karışık değilmiş gibi.Bknz.
void *value = NULL;
template <typename T>
T f(T data){return data;}
template <>
string f(string data){return "str";}
Hayır, type deduction yapamaz hala böyle.Template yazıp o template'lerin türüne göre özel olarak fonksiyon davranışını programlayabiliyoruz C++'ta. "Type'ına göre döndürmek istiyorum" kısmından bunu anladım en azından.
C++:template <typename T> T f(T data){return data;} template <> string f(string data){return "str";}
obj.name
obj.foo
obj.bar
yerine, ["name", "foo", "bar"] bir array ile assign işlemi yapabiliyoruz. // This filler is written keeping tiled's xml system in mind.
// It takes the structer as an array, if you are going to give only one object,
// give it as std::array<Structure, 1> struct;
// this is a recursive function,
// if possible it's going to loop.
// TODO: Handle inner nodes.
// TODO: Implement a way to find how many times the tags appear in the XML file.
template<size_t Index, size_t ObjArrSize, class Structure>
void Fill(std::array<Structure, ObjArrSize>& obj, std::string file_name ,std::string firstNode) {
// PugiXML parser is used for parsing the data in the first step.
// this part of the system requires us to use C++ 23 if we are going to use constexpr function.
// C++ 20 doesn't support constexpr version of this.
pugi::xml_document doc;
pugi::xml_parse_result res = doc.load_file(file_name.c_str());
const auto& name = Structure::tag;
// if somehow parsing files, Pugi supplies error information.
// so we throw ParseFaield exception to abort the program.
// user can ignore this exception by catching it
if(!res) {
throw ParseFailed((std::string("Parsing failed with error: ") + res.description()).c_str());
}
// for type shortening purposes, this is set.
auto attrlist = obj[Index].Reflection().Names;
auto map = doc.child(firstNode.c_str());
// since the function is recursive, this is necessary to prevent
// infinite loop
if constexpr (Index < ObjArrSize) {
// Pugi doesn't supply binary + operator.
// TODO: Implement binary + operator for pugi::xml_node.
// thus we nned to iterate through the iterator
auto child = map.begin();
// pugi child function actually gets the first sibling
// of the child (node), but for continuesly iterating,
// it doesn't supply a iterator to that child.
// so we first iterate to first sibling of the wanted node
// if name doesn't exist, it's gonna go into infinite loop
// when pugi reaches the end of the file or end of the nodes,
// it's gonna return an empty string as name.
while(std::string((*child).name()) != name or std::string((*child).name()) == "") {
child++;
}
// then we iterate to the node we want using Index
for(int j = 0; j < Index; j++) {
child++;
}
// below is self explonatery, yet let me explain.
// if the tag set by structure is matches with any child
// do below;
if(name == std::string((*child).name())) {
// set the matching variables with attribute list.
// example;
// let's say attribute is width and is in the child,
// and if it's also in the structure (must use the same name)
// it'll be set.
for(int i = 0; i < obj[Index].Reflection().MemberCount; i++) {
SetByName(obj[Index], attrlist[i], (*child).attribute(attrlist[i]).value());
}
// TODO: handle inners as generic as this is.
obj[Index].SetInner((*child).first_child());
};
// Recursive call
Fill<Index + 1, ObjArrSize, Structure>(obj, file_name, firstNode);
}
}
any_cast<int>(GetByName(obj, "bar");
. Amacım bu aradaki cast'i eleyip direkt olarak o türdeki nesneyi verebilmek.variant kullanmayı denedin mi ?Merhaba;
Gorgon: Summary üzerinde map vb sistemler için bir şey geliştiriyorum. Gorgon'un içerisinde Struct.h kısmına baktığınızda reflection becerisini olduğunu göreceksiniz. Bu becerisinden yararlanıp setbyname adında bir fonksiyon oluşturdum. Şimdi aynı mantıkla getbyname oluşturmak istiyorum.
Aşağıda SetByName var.
C++:// Using Gorgon's Reflection system to handle member assignments. namespace internal { template<class T_, int Ind> // Sets the member by name if the name exists in the structure's reflection. void SetByName_setif(T_ &obj, const std::string &name, const std::string &value) { if(T_::Reflection().Names[Ind] == name) obj.*(T_::ReflectionType::template Member<Ind>::MemberPointer()) = Gorgon::String::To<typename T_::ReflectionType::template Member<Ind>::Type>(value); } // Since we can't travel template members in run time, we use Gorgon Sequence for to do that using template parameters. template<class T_, int ...S_> void SetByName_expand(Gorgon::TMP::Sequence<S_...>, T_ &obj, const std::string &name, const std::string &value) { (SetByName_setif<T_, S_>(obj, name, value), ...); } } // Caller for the above. template<class T_> void SetByName(T_ &obj, const std::string &name, const std::string &value) { internal::SetByName_expand(typename Gorgon::TMP::Generate<T_::ReflectionType::MemberCount>::Type{}, obj, name, value); }
Aynı mantıktan yola çıkarak önce şunu yaptım;
C++:template<class T_, int Ind> auto GetByName_getif(const T_& obj, const char* name) -> T_::ReflectionType::template Member<Ind>::Type { if (T_::Reflection().Names[Ind] == name) { return obj.*(T_::ReflectionType::template Member<Ind>::MemberPointer()); } return {}; } template <class T_, int ...S_> auto GetByName_expand(Gorgon::TMP::Sequence<S_...>, const T_& obj, const char * name) { return (GetByName_getif<T_, S_>(obj, name), ...); } template <class T_> auto GetByName_(const T_& obj, const char * name) { return GetByName_expand(typename Gorgon::TMP::Generate<T_::ReflectionType::MemberCount>::Type{}, obj, name); }
Fakat yukarıdakinin problemi, ilk returnden sonra duracak olması. İlk yazarken aklıma gelmemişti duracağı. :') Sonrasındastd::any
'den yararlanıp şöyle bir şey yazdım;
C++:class Get { private: std::any value; template<class T_, int Ind> void ByName_getif(const T_& obj, const std::string& name) { value.reset(); if (T_::Reflection().Names[Ind] == name) value = obj.*(T_::ReflectionType::template Member<Ind>::MemberPointer()); } template <class T_, int ...S_> void ByName_expand(Gorgon::TMP::Sequence<S_...>, const T_& obj, const std::string& name) { (ByName_getif<T_, S_>(obj, name), ...); } public: template <class T_> std::any ByName(const T_& obj, const std::string& name) { ByName_expand(typename Gorgon::TMP::Generate<T_::ReflectionType::MemberCount>::Type{}, obj, name); return value; } template <class T_> std::any operator()(const T_& obj, const std::string& name) { return ByName(obj, name); } }; Get GetByName;
Fakat hala any kullandığım için, cast etmem gerekiyor. cast olmadan otomatik olarak type'ına göre döndürebilmek istiyorum. İyice beynim yanmaya başladı. Nasıl çözebilirim?
@Vavien.
Gelebilecek typelar sabit olsa, variant mantıklı olur. variant ayrıca yine cast gerektiriyor.variant kullanmayı denedin mi ?
std::visit - cppreference.com bununla çalışması lazım diye hatırlıyorum.Gelebilecek typelar sabit olsa, variant mantıklı olur. variant ayrıca yine cast gerektiriyor.
std::variant'ı kullanabilmem için gelecek typelar sabit olmalı. Yani variant'ın template parameterleri compile time'da belirlenmiş olmalı. Ek olarak visitor birden fazla türü döndüremez;std::visit - cppreference.com bununla çalışması lazım diye hatırlıyorum.
İstediğin bir çözüm değil biliyorum fakat cast işlemini kullanıcıdan kurtarabiliriz.Amacım bu aradaki cast'i eleyip direkt olarak o türdeki nesneyi verebilmek.
template <typename U, class T_>
U operator()(const T_& obj, const std::string& name) {
return std::any_cast<U>(ByName(obj, name));
// auto bar = GetByName<int>(foo, "bar")
}