Search code examples
c++11templateslambdadeclspec

Tempate defined by return value of lambda function


Let it be a template with requirement of such behavior:

template<typename MyActionLambda>
void enumerateChildrenByTag(QDomNodeList& list, const QString& tag, MyActionLambda action )
{
    for(int i = 0; i < list.size(); i++) {
        QDomElement el = list.item(i).firstChildElement(tag);
        while(!el.isNull())
        {
            if( typeid(decltype(action(el))) == typeid(SomeType) )
            {
                    auto res = action(el)
                    // do something with res
            }
            else
                    // do something with action(el)

            el = el.nextSiblingElement(tag);
        }
    }
}

this obviously would be impossible in way it is written for lambda to have void return type, because both branches of if() should be legal. Is there a simpler way to resolve this except making declspec as a default value of template parameter and specialize two templates?


Solution

  • With C++17 you could write

    if constexpr( std::is_same<decltype(action(el)),SomeType>::value )
        auto res = action(el);
    else
    { /* do something else */ }
    

    But I think this kind of construct is much more readable using a templated function which you can specialize for SomeType:

    template<class X>
    void someFunction(const X& x) { /* standard case */ }
    template<>
    void someFunction(const SomeType& x) { /* SomeType case */ }
    

    and inside your loop you just call:

    for(QDomElement el = list.item(i).firstChildElement(tag);
                    !el.isNull(); el = el.nextSiblingElement(tag))
        someFunction(action(el));