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?
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;
}
};