当前位置: 首页 > 知识库问答 >
问题:

使用SFINAE确保可变参数包参数是由特定类型导出的

夏侯昊明
2023-03-14

我目前有一个具有以下结构的类层次结构:

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

所以我想在我的抽象基类中的::addItem()。。。要求如下:

  • 我将传入对象的地址(函数接受指向对象的指针),因为基类存储了一个列表shared_ptr

这就是我迄今为止所做的尝试:

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_sameis_base_of连接和其他std函数模板...另一个问题是如何正确扩展if语句中的参数包。...是否有特定的符号,或者我必须使用折叠表达式?


共有1个答案

阙博容
2023-03-14

只需添加一个重载,并使用初始值设定项列表

addItem(std::initializer_list<Base*> items)
{
    for(auto item: items)
        addItem(item);
}

您只需使用带括号的初始化列表调用它:a1.add项目({

 类似资料:
  • 我正在尝试将一个参数传递给包含在主jsp中的jsp文件。从我在网上看到的使用c:set 虽然当我尝试使用包含的jsp页面中的变量时,似乎只有一个参数通过(第二个没有使用c: set) 没有崩溃,但我可以看到myArg01为空

  • 5.7. 可变参数 参数数量可变的函数称为为可变参数函数。典型的例子就是fmt.Printf和类似函数。Printf首先接收一个的必备参数,之后接收任意个数的后续参数。 在声明可变参数函数时,需要在参数列表的最后一个参数类型之前加上省略符号“...”,这表示该函数会接收任意数量的该类型参数。 gopl.io/ch5/sum func sum(vals...int) int { total

  • 问题内容: 我正在努力查看将值传递给函数时使用哪种方法是否有明显的优势。下面的代码可能不是解释我要做出的决定的最佳示例,但我认为这是最容易理解的示例。 可变参数方法 数组参数法 两种技术中的哪一种是首选?如果是这样,为什么(速度,可靠性或只是易于阅读)?谢谢。 问题答案: 我认为没有速度差异。因为,在功能内部,您可以像一样使用。 我认为如果参数数量较少(例如小于5个),则因为易于阅读,可能是一个更

  • 问题内容: 我了解协方差和逆方差。但是有一件小事我无法理解。在Coursera的“ Scala中的函数式编程”课程中,Martin Ordersky提到: 函数的参数类型是互变的,而返回类型是协变的 因此,例如在Java中,让extends出现。并让一个函数为: 我有函数调用为 所以基本上就是这样。根据Wiki,协方差是“从宽到窄转换”。在上面,我们正在从狗变成动物。所以论点类型不是协变而是协变吗

  • 局部变量 仅在代码块或函数中才可见的变量(参考函数章节的局部变量部分)。 环境变量 会影响用户及shell行为的变量。 一般情况下,每一个进程都有自己的“环境”(environment),也就是一组该进程可以访问到的变量。从这个意义上来说,shell表现出与其他进程一样的行为。 每当shell启动时,都会创建出与其环境对应的shell环境变量。改变或增加shell环境变量会使shell更新其自身的

  • 问题内容: 该代码无法编译,编译器说f含糊。但是我认为第二种方法可以解决什么问题? 问题答案: 这是因为无法确定该方法调用是应调用变量args还是应调用float和变量args。 Java决定以这种方式来调用拓宽>装箱>变量args的方法,但是在这种情况下,两者都具有变量args。 在这种情况下,基本上将char扩展为浮动。 Java基元的扩展顺序为: