使用 SFINAE 确保可变参数包参数派生自特定类型
Using SFINAE to ensure the Variadic Parameter Pack Arguments are Derived of a Specific Type
我目前有一个具有以下结构的 class 层次结构:
#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;
}
所以我正在考虑在我的抽象基础 class 中的 ::addItem()
函数上使用带有 SFINAE 的可变参数函数模板...要求如下:
- 我将传递对象的地址(该函数采用指向对象的指针),因为基 class 存储了
shared_ptr<Base>
个对象的列表。
- 我需要确保 Variadic Function Template 的参数包中的每个参数都是
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
}
}
我正在尝试将我的普通成员函数转换为如上所述的行为,因为我正在考虑同时使用 Varidiac 函数模板和 SFINAE 来确保参数包的每个参数至少来自 Base
.
我不确定正确的语法是什么,也不确定要使用的库函数集...我试过使用 is_same
、is_base_of
、conjunction
,和其他标准函数模板...另一个问题是如何在 if 语句中正确扩展参数包。 ...
是否有特定的表示法,或者我是否必须使用折叠表达式?
添加一个需要 initializer_list
:
的重载真的会容易得多
addItem(std::initializer_list<Base*> items)
{
for(auto item: items)
addItem(item);
}
您只需使用花括号初始化列表来调用它:a1.addItem({&a2, &a3, &b1, &b2, &b3});
。
我目前有一个具有以下结构的 class 层次结构:
#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;
}
所以我正在考虑在我的抽象基础 class 中的 ::addItem()
函数上使用带有 SFINAE 的可变参数函数模板...要求如下:
- 我将传递对象的地址(该函数采用指向对象的指针),因为基 class 存储了
shared_ptr<Base>
个对象的列表。 - 我需要确保 Variadic Function Template 的参数包中的每个参数都是
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
}
}
我正在尝试将我的普通成员函数转换为如上所述的行为,因为我正在考虑同时使用 Varidiac 函数模板和 SFINAE 来确保参数包的每个参数至少来自 Base
.
我不确定正确的语法是什么,也不确定要使用的库函数集...我试过使用 is_same
、is_base_of
、conjunction
,和其他标准函数模板...另一个问题是如何在 if 语句中正确扩展参数包。 ...
是否有特定的表示法,或者我是否必须使用折叠表达式?
添加一个需要 initializer_list
:
addItem(std::initializer_list<Base*> items)
{
for(auto item: items)
addItem(item);
}
您只需使用花括号初始化列表来调用它:a1.addItem({&a2, &a3, &b1, &b2, &b3});
。