Commit bedc1e62 authored by Tomáš Jakubec's avatar Tomáš Jakubec
Browse files

Improvement of traits algorithms (to be renamed as traits operations)

parent 908a5c78
Loading
Loading
Loading
Loading
+86 −18
Original line number Original line Diff line number Diff line
@@ -3,7 +3,7 @@
#include "../src/UnstructuredMesh/UnstructuredMesh.h"
#include "../src/UnstructuredMesh/UnstructuredMesh.h"
#include "../src/Traits/MemberApproach/MemberApproach.h"
#include "../src/Traits/MemberApproach/MemberApproach.h"
#include "../src/Traits/Traits.h"
#include "../src/Traits/Traits.h"

#include "../src/Singleton/Singleton.h"
#include <chrono>
#include <chrono>
#include <functional>
#include <functional>
#include <type_traits>
#include <type_traits>
@@ -322,14 +322,6 @@ void testMemberRef(){
    DBGVAR(e, ClassC<>());
    DBGVAR(e, ClassC<>());
}
}


void testTraitsAlgorithms() {
    ExportTest e1, e2;
    ExportTest res = e1 + e2;
    std::vector<ExportTest> vec(40, ExportTest());

    DBGVAR(2.45*e1,e1 + e2, e1, e2,HasDefaultArithmeticTraits<int>::value, max(e2), min(e2), max(vec));
}



struct NumStruct {
struct NumStruct {
    double data;
    double data;
@@ -340,10 +332,32 @@ MAKE_ATTRIBUTE_TRAIT(NumStruct, data);
struct NumStruct2 {
struct NumStruct2 {
    double data1;
    double data1;
    double data2;
    double data2;

    NumStruct2(double d1 = 0.0, double d2 = 0.0): data1(d1), data2(d2){}
};
};
MAKE_ATTRIBUTE_TRAIT(NumStruct2, data1, data2);
MAKE_ATTRIBUTE_TRAIT(NumStruct2, data1, data2);




void testTraitsAlgorithms() {
    ExportTest e1, e2;
    ExportTest res = e1 + e2;
    std::vector<ExportTest> vec(40, ExportTest());

    DBGVAR(2.45*e1,e1 + e2, e1, e2,HasDefaultArithmeticTraits<int>::value, max(e2), min(e2), max(vec));

    NumStruct2 ns{21,15}, ns2{2,3};
    DBGVAR(ns * ns2,
           -(ns + 4 * ns2),
           max(-(ns + 4 * ns2)),
           max(abs(-(ns + 4 * ns2))),
           log(ns), exp(log(ns)),
           pow(sqrt(ns), 2)
           );
}




template <unsigned int Index>
template <unsigned int Index>
const MemberReference<tempData, DefaultArithmeticTraits<tempData>::traitsType::type<Index>, DefaultArithmeticTraits<tempData>::traitsType::refType<Index>>
const MemberReference<tempData, DefaultArithmeticTraits<tempData>::traitsType::type<Index>, DefaultArithmeticTraits<tempData>::traitsType::refType<Index>>
getReference() {
getReference() {
@@ -1048,6 +1062,24 @@ void testNumericTraitsPerformance() {
    duration = 0;
    duration = 0;




    DBGMSG("numeric traits = +");

    start = clock.now();
    res2 = NumStruct2();
    for(int rep = 0; rep < maxRep; rep++){
        for(size_t i = 0; i < numVec2.size(); i++) {
            res2 = res2 + numVec2[i];
        }
        duration += (clock.now() - start).count();
        deviation += (clock.now() - start).count() * (clock.now() - start).count();
        start = clock.now();
    }

    avgDuration = duration / maxRep;
    DBGVAR(res2, avgDuration , sqrt(((deviation)- maxRep * pow(avgDuration,2)) / (maxRep - 1)));
    deviation = 0;
    duration = 0;

    DBGMSG("\n","ExportTest performance, direct approach");
    DBGMSG("\n","ExportTest performance, direct approach");


    std::vector<ExportTest> vec3(size, ExportTest());
    std::vector<ExportTest> vec3(size, ExportTest());
@@ -1093,6 +1125,9 @@ void testNumericTraitsPerformance() {
    deviation = 0;
    deviation = 0;
    duration = 0;
    duration = 0;





}
}




@@ -1297,15 +1332,15 @@ template <typename Class, typename T>
class Func {
class Func {
public:
public:


    template <typename U = T>
    template <typename U = T,  typename refType>
    auto operator()(unsigned int index, const MemberApproach<Class, T>&, const std::string& name)
    auto operator()(unsigned int index, const MemberReference<Class, T, refType>&, const std::string& name)
    -> typename std::enable_if<!(HasDefaultTraits<U>::value)>::type
    -> typename std::enable_if<!(HasDefaultTraits<U>::value)>::type
    {
    {
        DBGVAR(Singleton<Depth>::getInstance().value,index, name);
        DBGVAR(Singleton<Depth>::getInstance().value,index, name);
    }
    }


    template <typename U = T>
    template <typename U = T, typename refType>
    auto operator()(unsigned int index, const MemberApproach<Class, T>&, const std::string& name)
    auto operator()(unsigned int index, const MemberReference<Class, T, refType>&, const std::string& name)
    -> typename std::enable_if<HasDefaultTraits<U>::value>::type
    -> typename std::enable_if<HasDefaultTraits<U>::value>::type
    {
    {
        DBGVAR(Singleton<Depth>::getInstance().value,index, name);
        DBGVAR(Singleton<Depth>::getInstance().value,index, name);
@@ -1602,7 +1637,7 @@ class TestMemberReference{




template <typename Class, typename ValueType>
template <typename Class, typename ValueType>
class TestMemberReference<Class, ValueType, ValueType Class::*> : MemberApproach<Class, ValueType>{
class TestMemberReference<Class, ValueType, ValueType Class::*> /*: MemberApproach<Class, ValueType>*/{


    using refType = ValueType Class::*;
    using refType = ValueType Class::*;
public:
public:
@@ -1902,7 +1937,7 @@ void testTraitPerformance() {
    DBGVAR(res, avgDuration , sqrt(((deviation)- maxRep * pow(avgDuration,2)) / (maxRep - 1)));
    DBGVAR(res, avgDuration , sqrt(((deviation)- maxRep * pow(avgDuration,2)) / (maxRep - 1)));
    deviation = 0;
    deviation = 0;
    duration = 0;
    duration = 0;

/*
    DBGMSG("member reference virtual");
    DBGMSG("member reference virtual");
    const MemberApproach<ExportTest, double>* MA = new MemberReference<ExportTest, double, decltype (&ExportTest::attrDouble)>(&ExportTest::attrDouble);
    const MemberApproach<ExportTest, double>* MA = new MemberReference<ExportTest, double, decltype (&ExportTest::attrDouble)>(&ExportTest::attrDouble);
    start = clock.now();
    start = clock.now();
@@ -1920,7 +1955,7 @@ void testTraitPerformance() {
    DBGVAR(res, avgDuration , sqrt(((deviation)- maxRep * pow(avgDuration,2)) / (maxRep - 1)));
    DBGVAR(res, avgDuration , sqrt(((deviation)- maxRep * pow(avgDuration,2)) / (maxRep - 1)));
    deviation = 0;
    deviation = 0;
    duration = 0;
    duration = 0;

*/


    DBGMSG("traits");
    DBGMSG("traits");
    start = clock.now();
    start = clock.now();
@@ -2290,6 +2325,38 @@ void testTraitsTuple(){
    DBGVAR(foo(t), t);
    DBGVAR(foo(t), t);
}
}


/*
template <unsigned int n, unsigned int _n = 1>
constexpr typename std::enable_if<(_n == n), unsigned int>::type
factorial(){
    return _n;
}

template <unsigned int n, unsigned int _n = 1>
constexpr typename std::enable_if<(_n < n), unsigned int>::type
factorial(){
    return factorial<n,_n+1>() * _n;
}
*/
namespace Impl {
template <unsigned int n, unsigned int _n = 1>
constexpr typename std::enable_if<(_n == n), unsigned int>::type
factorial(){
    return _n;
}

template <unsigned int n, unsigned int _n = 1>
constexpr typename std::enable_if<(_n < n), unsigned int>::type
factorial(){
    return Impl::factorial<n,_n+1>() * _n;
}
}


void testFactorial() {

    DBGVAR(Impl::factorial<5>());
}


int main()
int main()
{
{
@@ -2308,8 +2375,9 @@ int main()
    //testJson();
    //testJson();
    //testTestTraits();
    //testTestTraits();
    //testTraitsAlgorithms();
    //testTraitsAlgorithms();
    //testNumericTraitsPerformance();
    testNumericTraitsPerformance();
    testTraitsTuple();
    //testTraitsTuple();
    //testFactorial();
    return 0;
    return 0;
}
}


+84 −51
Original line number Original line Diff line number Diff line
@@ -4,22 +4,45 @@
#include <utility>
#include <utility>





/**
/**
 * @brief The MemberApproach class
 * @brief The DirectReference struct determines that the
 * Generic abstract class providing the approach to
 * reference can provide direct approach to the member.
 * any attribute of a class using getValue and setValue
 */
 */
template <typename Class, typename ValueType>
struct DirectReference{
class MemberApproach{
    static constexpr std::true_type is_direct{};
public:
    virtual ValueType getValue(const Class*) const = 0;
    virtual void setValue(Class*, const ValueType&) const = 0;

    virtual ValueType getValue(const Class&) const = 0;
    virtual void setValue(Class&, const ValueType&) const = 0;
};
};







namespace Impl {
template <typename T, typename = void>
struct IsDirectReference : public std::false_type {};

template <typename T>
struct IsDirectReference
        <
        T,
        typename std::enable_if<T::is_direct>::type
        >
        : public std::true_type {};

} // Impl



/**
 * @brief The IsDirectReference struct inherits
 * @ref std::true_type if the class MemberReference provides direct
 * approach to the member using function getAttr.
 */
template <typename T>
struct IsDirectReference : public Impl::IsDirectReference<T> {};



template<typename Class, typename ValueType, typename Ref>
template<typename Class, typename ValueType, typename Ref>
class MemberReference{
class MemberReference{
    static_assert (std::is_same<Ref, ValueType Class::*>::value,
    static_assert (std::is_same<Ref, ValueType Class::*>::value,
@@ -29,7 +52,7 @@ class MemberReference{




template <typename Class, typename ValueType>
template <typename Class, typename ValueType>
class MemberReference<Class, ValueType, ValueType Class::*> : public MemberApproach<Class, ValueType>{
class MemberReference<Class, ValueType, ValueType Class::*> : public DirectReference {


    using refType = ValueType Class::*;
    using refType = ValueType Class::*;


@@ -45,11 +68,11 @@ public:


    MemberReference(MemberReference<Class, ValueType, ValueType Class::*>&&) = default;
    MemberReference(MemberReference<Class, ValueType, ValueType Class::*>&&) = default;


    virtual ValueType getValue(const Class* c) const override {
    ValueType getValue(const Class* c) const {
        return c->*ref;
        return c->*ref;
    }
    }


    virtual void setValue(Class* c, const ValueType& val) const override {
    void setValue(Class* c, const ValueType& val) const {
        c->*ref = val;
        c->*ref = val;
    }
    }


@@ -57,11 +80,11 @@ public:
        return c->*ref;
        return c->*ref;
    }
    }


    virtual ValueType getValue(const Class& c) const override {
    ValueType getValue(const Class& c) const {
        return c.*ref;
        return c.*ref;
    }
    }


    virtual void setValue(Class& c, const ValueType& val) const override {
    void setValue(Class& c, const ValueType& val) const {
        c.*ref = val;
        c.*ref = val;
    }
    }


@@ -75,7 +98,7 @@ public:




template <typename Class, typename ValueType>
template <typename Class, typename ValueType>
class MemberReference<Class, ValueType, ValueType& (Class::*)()> : public MemberApproach<Class, ValueType>{
class MemberReference<Class, ValueType, ValueType& (Class::*)()> : public DirectReference {


    using refType = ValueType& (Class::*)();
    using refType = ValueType& (Class::*)();


@@ -89,21 +112,29 @@ public:
        //ref = referenceToMember;
        //ref = referenceToMember;
    }
    }


    virtual ValueType getValue(const Class* c) const override {
    ValueType getValue(const Class* c) const {
        return (c->*ref)();
    }

    ValueType& getAttr(Class* c) const {
        return (c->*ref)();
        return (c->*ref)();
    }
    }


    virtual void setValue(Class* c, const ValueType& val) const override {
    void setValue(Class* c, const ValueType& val) const {
        (c->*ref)() = val;
        (c->*ref)() = val;
    }
    }
    virtual ValueType getValue(const Class& c) const override {
    ValueType getValue(const Class& c) const {
        return (c.*ref)();
        return (c.*ref)();
    }
    }


    virtual void setValue(Class& c, const ValueType& val) const override {
    void setValue(Class& c, const ValueType& val) const {
        (c.*ref)() = val;
        (c.*ref)() = val;
    }
    }


    ValueType& getAttr(Class& c) const {
        return (c->*ref)();
    }

};
};




@@ -115,7 +146,7 @@ class MemberReference<
        ValueType,
        ValueType,
        std::pair<ValueType (Class::*)(), void (Class::*)(const ValueType&)>
        std::pair<ValueType (Class::*)(), void (Class::*)(const ValueType&)>
>
>
: public MemberApproach<Class, ValueType>{
{


    using getter = ValueType (Class::*)();
    using getter = ValueType (Class::*)();
    getter const refGet;
    getter const refGet;
@@ -130,19 +161,19 @@ public:
         //refSet = getSet.second;
         //refSet = getSet.second;
     }
     }


     virtual ValueType getValue(const Class* c) const override {
     ValueType getValue(const Class* c) const {
         return (c->*refGet)();
         return (c->*refGet)();
     }
     }


     virtual void setValue(Class* c, const ValueType& val) const override {
     void setValue(Class* c, const ValueType& val) const {
         (c->*refSet)(val);
         (c->*refSet)(val);
     }
     }


     virtual ValueType getValue(const Class& c) const override {
     ValueType getValue(const Class& c) const {
         return (c.*refGet)();
         return (c.*refGet)();
     }
     }


     virtual void setValue(Class& c, const ValueType& val) const override {
     void setValue(Class& c, const ValueType& val) const {
         (c.*refSet)(val);
         (c.*refSet)(val);
     }
     }
};
};
@@ -154,7 +185,7 @@ class MemberReference<
        ValueType,
        ValueType,
        std::pair<ValueType (Class::*)() const, void (Class::*)(const ValueType&)>
        std::pair<ValueType (Class::*)() const, void (Class::*)(const ValueType&)>
>
>
: public MemberApproach<Class, ValueType>{
{


    using getter = ValueType (Class::*)() const;
    using getter = ValueType (Class::*)() const;
    getter const refGet;
    getter const refGet;
@@ -169,19 +200,19 @@ public:
         //refSet = getSet.second;
         //refSet = getSet.second;
     }
     }


     virtual ValueType getValue(const Class* c) const override {
     ValueType getValue(const Class* c) const {
         return (c->*refGet)();
         return (c->*refGet)();
     }
     }


     virtual void setValue(Class* c, const ValueType& val) const override {
     void setValue(Class* c, const ValueType& val) const {
         (c->*refSet)(val);
         (c->*refSet)(val);
     }
     }


     virtual ValueType getValue(const Class& c) const override {
     ValueType getValue(const Class& c) const {
         return (c.*refGet)();
         return (c.*refGet)();
     }
     }


     virtual void setValue(Class& c, const ValueType& val) const override {
     void setValue(Class& c, const ValueType& val) const {
         (c.*refSet)(val);
         (c.*refSet)(val);
     }
     }
};
};
@@ -193,7 +224,7 @@ class MemberReference<
        ValueType,
        ValueType,
        std::pair<const ValueType& (Class::*)() const, void (Class::*)(const ValueType&)>
        std::pair<const ValueType& (Class::*)() const, void (Class::*)(const ValueType&)>
>
>
: public MemberApproach<Class, ValueType>{
{


    using getter = const ValueType& (Class::*)() const;
    using getter = const ValueType& (Class::*)() const;
    getter const refGet;
    getter const refGet;
@@ -208,19 +239,19 @@ public:
         //refSet = getSet.second;
         //refSet = getSet.second;
     }
     }


     virtual ValueType getValue(const Class* c) const override {
     ValueType getValue(const Class* c) const {
         return (c->*refGet)();
         return (c->*refGet)();
     }
     }


     virtual void setValue(Class* c, const ValueType& val) const override {
     void setValue(Class* c, const ValueType& val) const {
         (c->*refSet)(val);
         (c->*refSet)(val);
     }
     }


     virtual ValueType getValue(const Class& c) const override {
     ValueType getValue(const Class& c) const {
         return (c.*refGet)();
         return (c.*refGet)();
     }
     }


     virtual void setValue(Class& c, const ValueType& val) const override {
     void setValue(Class& c, const ValueType& val) const {
         (c.*refSet)(val);
         (c.*refSet)(val);
     }
     }
};
};
@@ -232,7 +263,7 @@ class MemberReference<
        ValueType,
        ValueType,
        std::pair<const ValueType& (Class::*)(), void (Class::*)(const ValueType&)>
        std::pair<const ValueType& (Class::*)(), void (Class::*)(const ValueType&)>
>
>
: public MemberApproach<Class, ValueType>{
{


    using getter = const ValueType& (Class::*)();
    using getter = const ValueType& (Class::*)();
    getter const refGet;
    getter const refGet;
@@ -247,19 +278,19 @@ public:
         //refSet = getSet.second;
         //refSet = getSet.second;
     }
     }


     virtual ValueType getValue(const Class* c) const override {
     ValueType getValue(const Class* c) const {
         return (c->*refGet)();
         return (c->*refGet)();
     }
     }


     virtual void setValue(Class* c, const ValueType& val) const override {
     void setValue(Class* c, const ValueType& val) const {
         (c->*refSet)(val);
         (c->*refSet)(val);
     }
     }


     virtual ValueType getValue(const Class& c) const override {
     ValueType getValue(const Class& c) const {
         return (c.*refGet)();
         return (c.*refGet)();
     }
     }


     virtual void setValue(Class& c, const ValueType& val) const override {
     void setValue(Class& c, const ValueType& val) const {
         (c.*refSet)(val);
         (c.*refSet)(val);
     }
     }
};
};
@@ -267,7 +298,8 @@ public:




template <typename Class, typename ValueType>
template <typename Class, typename ValueType>
class MemberReference<Class, ValueType, std::pair<ValueType&(*)(Class&), const ValueType&(*)(const Class&)>> : public MemberApproach<Class, ValueType>{
class MemberReference<Class, ValueType, std::pair<ValueType&(*)(Class&), const ValueType&(*)(const Class&)>>
: public DirectReference {


    using setter = ValueType& (*)(Class&);
    using setter = ValueType& (*)(Class&);


@@ -289,21 +321,21 @@ public:


    MemberReference(MemberReference<Class, ValueType, std::pair<ValueType&(*)(Class&), const ValueType&(*)(const Class&)>>&&) = default;
    MemberReference(MemberReference<Class, ValueType, std::pair<ValueType&(*)(Class&), const ValueType&(*)(const Class&)>>&&) = default;


    virtual ValueType getValue(const Class* c) const override {
    ValueType getValue(const Class* c) const {
        return get(*c);
        return get(*c);
    }
    }




    virtual void setValue(Class* c, const ValueType& val) const override {
    void setValue(Class* c, const ValueType& val) const {
        set(*c) = val;
        set(*c) = val;
    }
    }


    virtual ValueType getValue(const Class& c) const override {
    ValueType getValue(const Class& c) const {
        return get(c);
        return get(c);
    }
    }




    virtual void setValue(Class& c, const ValueType& val) const override {
    void setValue(Class& c, const ValueType& val) const {
        set(c) = val;
        set(c) = val;
    }
    }


@@ -318,7 +350,8 @@ public:




template <typename Class, typename ValueType>
template <typename Class, typename ValueType>
class MemberReference<Class, ValueType, std::pair<ValueType&(*)(Class*), const ValueType&(*)(const Class*)>> : public MemberApproach<Class, ValueType>{
class MemberReference<Class, ValueType, std::pair<ValueType&(*)(Class*), const ValueType&(*)(const Class*)>>
: public DirectReference {


    using setter = ValueType& (*)(Class*);
    using setter = ValueType& (*)(Class*);


@@ -340,21 +373,21 @@ public:


    MemberReference(MemberReference<Class, ValueType, std::pair<ValueType&(*)(Class*), const ValueType&(*)(const Class*)>>&&) = default;
    MemberReference(MemberReference<Class, ValueType, std::pair<ValueType&(*)(Class*), const ValueType&(*)(const Class*)>>&&) = default;


    virtual ValueType getValue(const Class* c) const override {
    ValueType getValue(const Class* c) const {
        return get(c);
        return get(c);
    }
    }




    virtual void setValue(Class* c, const ValueType& val) const override {
    void setValue(Class* c, const ValueType& val) const {
        set(c) = val;
        set(c) = val;
    }
    }


    virtual ValueType getValue(const Class& c) const override {
    ValueType getValue(const Class& c) const {
        return get(&c);
        return get(&c);
    }
    }




    virtual void setValue(Class& c, const ValueType& val) const override {
    void setValue(Class& c, const ValueType& val) const {
        set(&c) = val;
        set(&c) = val;
    }
    }


+66 −5
Original line number Original line Diff line number Diff line
@@ -3,7 +3,6 @@
#include "MemberApproach/MemberApproach.h"
#include "MemberApproach/MemberApproach.h"
#include <string>
#include <string>
#include <memory>
#include <memory>
#include "../Singleton/Singleton.h"
#include <functional>
#include <functional>


template<typename Class, typename...RefTypes>
template<typename Class, typename...RefTypes>
@@ -74,6 +73,19 @@ public:
    }
    }




    template<unsigned int Index>
    type<Index>& getAttr(Class* c) const {
        static_assert (IsDirectReference<memRefType<Index>>::value, "The current reference to the member does not provide direct approach.");
        return getReference<Index>()->getAttr(c);
    }

    template<unsigned int Index>
    type<Index>& getAttr(Class& c) const {
        static_assert (IsDirectReference<memRefType<Index>>::value, "The current reference to the member does not provide direct approach.");
        return getReference<Index>().getAttr(c);
    }


    template<unsigned int Index>
    template<unsigned int Index>
    const char* getName() const {
    const char* getName() const {
        return refs.MemRefs<Index, void>::name;
        return refs.MemRefs<Index, void>::name;
@@ -261,12 +273,61 @@ public:







template<typename Class>
template<typename Class>
class DefaultIOTraits : public Traits<Class> {};
class DefaultIOTraits : public Traits<Class> {};


template<typename Class>
template<typename Class>
class DefaultArithmeticTraits : public Traits<Class> {};
class DefaultArithmeticTraits : public Traits<Class> {};



#include "CustomTypeTraits.h"

namespace Impl {
template <unsigned int Index, unsigned int ...Indexes>
struct TraitedAttributeGetter{
    template<typename TraitT, typename = typename std::enable_if<HasDefaultArithmeticTraits<TraitT>::value>::type>
    static auto& get(TraitT& arg){
        return TraitedAttributeGetter<Indexes...>::get(DefaultArithmeticTraits<TraitT>::getTraits().template getAttr<Index>(arg));
    }

    template<typename TraitT, typename = typename std::enable_if<HasDefaultArithmeticTraits<TraitT>::value>::type>
    static auto& get(TraitT* arg){
        return TraitedAttributeGetter<Indexes...>::get(DefaultArithmeticTraits<TraitT>::getTraits().template getAttr<Index>(arg));
    }
};

template <unsigned int Index>
struct TraitedAttributeGetter<Index>{
    template<typename TraitT, typename = typename std::enable_if<HasDefaultArithmeticTraits<TraitT>::value>::type>
    static auto& get(TraitT& arg){
        return DefaultArithmeticTraits<TraitT>::getTraits().template getAttr<Index>(arg);
    }

    template<typename TraitT, typename = typename std::enable_if<HasDefaultArithmeticTraits<TraitT>::value>::type>
    static auto& get(TraitT* arg){
        return DefaultArithmeticTraits<TraitT>::getTraits().template getAttr<Index>(arg);
    }
};

} //Impl


template <typename ArythmeticTraitT, unsigned int ...Indexes, typename = typename std::enable_if<HasDefaultArithmeticTraits<ArythmeticTraitT>::value>::type>
auto& getTraitedAttribute(ArythmeticTraitT& arg){
    return Impl::TraitedAttributeGetter<Indexes...>::get(arg);
}


template <typename ArythmeticTraitT, unsigned int ...Indexes, typename = typename std::enable_if<HasDefaultArithmeticTraits<ArythmeticTraitT>::value>::type>
auto& getTraitedAttribute(ArythmeticTraitT* arg){
    return Impl::TraitedAttributeGetter<Indexes...>::get(arg);
}





#include "../Macros/MacroForEach.h"
#include "../Macros/MacroForEach.h"


#define IMPL_MEMREF_TYPE_CUSTOM(name, memberRef) decltype(memberRef)
#define IMPL_MEMREF_TYPE_CUSTOM(name, memberRef) decltype(memberRef)