Search code examples
c++templatesmacrosc++14generic-lambda

c++, a generic recursive template function to traverse tree like structures


I tried to traverse tree like structures with a generic recursive function without defining a recursive function in global each time for each structures.

//structure #1
class CA
{
public:
    std::string name;
    std::vector<CA*> vecChild;
};

and I create a tree with CA

auto root = new CA;
root->name = "root";
root->push_back(new CA);
auto& childA = root->back();
childA->name = "childA";
root->push_back(new CA);
auto& childB = root->back();
childB->name = "childB";
...

I can use this macro to traverse this structure and this can work with other tree like structures.

#define Combinator(obj, combinatorObjToContainer, containerNameOfObj, invokingGetCount, combinatorContainerToIndexingItem, TAnyObject, TAnyContainer, argEnterFunc, argLeaveFunc)\
{\
    std::function<void(TAnyObject, TAnyContainer)> RecursFunc = [&](auto& argObj, auto& argContainer)\
    {\
        argEnterFunc(argObj, argContainer);\
        for(size_t idx=0; idx<argObj combinatorObjToContainer containerNameOfObj invokingGetCount; ++idx)\
        {\
            RecursFunc(argObj, argObj combinatorObjToContainer containerNameOfObj combinatorContainerToIndexingItem [idx]);\
        }\
        argLeaveFunc(argObj, argContainer);\
    }\
}

It is hard to read but it works fine, I traverse the root of CA like this

Combinator(root, ->, vecChild, .size(), , CA*, std::vector<CA*>&, 
[&](auto& item, auto& vec)
{
    std::cout << item.name << std::endl;
},
[&](...)
{
});

Works with other structure, like this

struct MyData;
struct MyList
{
    int count;
    MyData* pItem;
};
struct MyData
{
    char* name;
    MyList* pLstChild;
};

Traverse the root of MyData

Combinator(root, ->, pLstChild, ->count, ->pItem, MyData*, MyList*, 
[&](auto& pItem, auto& pLst)
{
    std::cout << pItem->name << std::endl;
},
[&](...)
{
});

There is a major problem here.

I must specifies the type of the object and its container, because the lambda expression here is defined in recursive form.

Can macro deduce type like template function ? or maybe I should achieve this in other way ?


Solution

  • There is a major problem here.

    I must specifies the type of the object and its container, because the lambda expression here is defined in recursive form.

    Can macro deduce type like template function ?

    Are you sure a macro is necessary?

    Isn't better a template function and some methods, with fixed names, in classes (a sort of interface)?

    Anyway, if I understand correctly your macro, instead of TAnyObject you can use decltype(obj) and instead of TAnyContainer you can use decltype(containerNameOfObj)

    So something (sorry: code non tested)

    #define Combinator(obj, combinatorObjToContainer, containerNameOfObj, invokingGetCount, combinatorContainerToIndexingItem, argEnterFunc, argLeaveFunc)\
    {\
        std::function<void(decltype(obj), decltype(containerNameOfObj))> RecursFunc = [&](auto& argObj, auto& argContainer)\
        {\
            argEnterFunc(argObj, argContainer);\
            for(size_t idx=0; idx<argObj combinatorObjToContainer containerNameOfObj invokingGetCount; ++idx)\
            {\
                RecursFunc(argObj, argObj combinatorObjToContainer containerNameOfObj combinatorContainerToIndexingItem [idx]);\
            }\
            argLeaveFunc(argObj, argContainer);\
        }\
    }