В настоящее время у меня есть иерархия классов со следующей структурой:
#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() {}
}
И я могу использовать их следующим образом:
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;
}
Как видите, здесь много избыточности в звонках ::addItem()
. Я бы хотел использовать их так:
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;
}
Итак, я подумываю использовать шаблон функции Variadi c с SFINAE для функции ::addItem()
в моей абстрактной базе class ... Требования следующие:
- Я передам адрес объекта (функция принимает указатель на объект), поскольку базовый класс хранит список
shared_ptr<Base>
- Мне нужно убедиться, что каждый параметр с пакетом параметров шаблона функции Variadi c является производным типом
Base
.
Это то, что я до сих пор пытались:
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
}
}
Я пытаюсь преобразовать свою обычную функцию-член, чтобы она работала, как описано выше, поскольку я думаю об использовании как шаблонов функций Varidia c, так и SFINAE, чтобы убедиться, что каждый аргумент пакета параметров, по крайней мере, получен из Base
.
Я не уверен, какой правильный синтаксис или набор библиотечных функций следует использовать ... Я пробовал использовать is_same
, is_base_of
, conjunction
, а nd другие шаблоны функций std ... И еще одна проблема - как правильно расширить пакет параметров в операторе if. Есть ли специальная нотация c с ...
или мне нужно использовать выражения свёртки?