I currently have a class hierachy with the following structure:
#include <list>
#include <memory>
class Base {
protected:
std::list<std::shared_ptr<Base>> items_;
Base(){}
public:
addItem(Base* derived) {
// adds derived to items_
// and checks for duplicates
}
};
class DerivedA : public Base {
public:
DerivedA() {}
}
class DerivedB : public Base {
public:
DerivedB() {}
}
And I can use them as follows:
int main() {
DerivedA a1, a2, a3;
DerivedB b1, b2, b3;
a1.addItem(&a2); a1.addItem(&a3); a1.addItem(&b1); a1.addItem(&b2); a1.addItem(&b3);
a2.addItem(&a1); a2.addItem(&a3); a2.addItem(&b1); a2.addItem(&b2); a2.addItem(&b3);
a3.addItem(&a1); a3.addItem(&a2); a3.addItem(&b1); a3.addItem(&b2); a3.addItem(&b3);
b1.addItem(&a1); b1.addItem(&a2); b1.addItem(&a3); b1.addItem(&b2); b1.addItem(&b3);
b2.addItem(&a1); b2.addItem(&a2); b2.addItem(&a3); b2.addItem(&b1); b2.addItem(&b3);
b3.addItem(&a1); b3.addItem(&a2); b3.addItem(&a3); b3.addItem(&b1); b3.addItem(&b2);
return 0;
}
As you can see, there's a lot of redundancy within the ::addItem()
calls. What I would like to be able to do is use them like this:
int main() {
DerivedA a1, a2, a3;
DerivedB b1, b2, b3;
a1.addItem(&a2, &a3, &b1, &b2, &b3);
a2.addItem(&a1, &a2, &b1, &b2, &b3);
a3.addItem(&a1, &a2, &b1, &b2, &b3);
b1.addItem(&a1, &a2, &a3, &b2, &b3);
b2.addItem(&a1, &a2, &a3, &b1, &b3);
b3.addItem(&a1, &a2, &a3, &b1, &b2);
return 0;
}
So I'm thinking of using a Variadic Function Template with SFINAE on the ::addItem()
function within my abstract base class... The requirements are the following:
- I will be passing in the address of the object (the function takes a pointer to an object) since the base class stores a list of
shared_ptr<Base>
objects. - I need to make sure that every parameter with the parameter pack of the Variadic Function Template is a derived type of
Base
.
This is what I have attempted so far:
template<typename... Args, std::enable_if_t<std::is_base_of_v<Base, Args>...> { // How to use SFINAE here?
void addItem(Args*&& ... args) {
for ( auto& it : items_ ) {
// I also need to check a member variable from each of the `Args...` or derived types
// ::foo() is not shown in the above classes but exists in my code (its not important here)
// what is important is how do I expand (args) within an if statement?
if ( args->foo() == l->foo() ) {
// do something
}
// add to list
}
}
I'm trying to convert my normal member function to behave as I described above as I'm thinking of using both Varidiac Function Templates and SFINAE to make sure each argument of the parameter pack is at least derived from Base
.
I'm not sure what the proper syntax is nor the set of library functions are to use... I've tried using is_same
, is_base_of
, conjunction
, and other std function templates... And the other issue is how to properly expand the parameter pack in an if statement. Is there a specific notation with the ...
or do I have to use fold expressions?