c++c++17fold-expression

Combining fold expressions with lambdas in C++17


I have a class that is derived from a variadic template parameter. The derived class and base classes have a method with the same signature. The return type from each method is an object pointer. I would like to call that method for each base class using a fold expression in such a way that the return value of the fold expression is a return value of a method that belongs to a certain base class type, or nullptr if that base type is not present in the variadic template parameter.

The following working code illustrates this. I am returning a non-null pointer from Base::onMethod() if Base is one of the template parameters, and nullptr if it is not. In any case, onMethod() is called for all templates.

#include <iostream>  
#include <type_traits>  
  

struct Ret {  
};  
  
struct B1 {  
    Ret* onMethod() {  
        std::cerr << "B1\n";  
        return nullptr;  
    }  
};  
  
struct B2 {  
    Ret* onMethod() {  
        std::cerr << "B2\n";  
        return nullptr;  
    }  
};  
  
struct Base {  
    Ret* onMethod() {  
        std::cerr << "Base\n";  
        return new Ret();  
    }  
};  
  
template<typename... Bases>  
struct D : public Bases... {  
    Ret* onMethod() {  
        Ret* result = nullptr;                                                                                                                       
        ( [&result, this]() {                                                                                                                        
           auto* r = Bases::onMethod();                                                                                                              
           if constexpr (std::is_same<Bases, Base>::value) result = r;                                                                               
           }(), ...);                                                                                                                                
        return result;                                                                                                                               
    }                                                                                                                                                
};                                                                                                                                                   
                                                                                                                                                     
int main(void) {                                                                                                                                     
    D<B1, B2, Base> d;                                                                                                                               
    auto* r = d.onMethod();                                                                                                                          
    std::cerr << (r == nullptr) << std::endl;                                                                                                        
    D<B1, B2> d1;                                                                                                                                    
    auto r1 = d1.onMethod();                                                                                                                         
    std::cerr << (r1 == nullptr) << std::endl;                                                                                                       
    return 0;                                                                                                                                        
}     

To compile:

g++ -std=c++17 file.cpp

Notice that I have used a lambda in the onMethod() method of the derived class.

Is there a better and shorter syntax for D::onMethod(), potentially the one that does not use a lambda call?


Solution

  • Not sure how much more readable this is, but it doesn't use a lambda:

    template<typename... Bases>
    struct D : public Bases... {
        Ret* onMethod() {
            Ret* result = nullptr;
            Ret* temp = nullptr;
            (((std::is_same_v<Base, Bases> ? result : temp) = Bases::onMethod()), ...);
            return result;
        }
    };
    

    Demo