c++ - 作为 std::initializer_list 对象的抽象类

标签 c++ c++11

为了语法更清晰,我想使用 std::initializer_list 将对象列表发送到构造函数。然而,这些对象是抽象的,这会导致一个问题:在 VS 2013 中,它丢失了 vfptr 引用,给出了“R6025: pure virtual function call”运行时错误,而在 g++ 中它提示它“无法在编译期间分配抽象类型‘base’的对象”。我猜测编译器正在尝试复制对象(这是不可取的——它们可能很大),但仅在复制基类时成功,因此出现错误。我的问题是:是否有一种解决方案可以 (1) 避免复制对象,并且 (2) 不会过于冗长,从而否定“更简洁的语法”优势?下面的代码说明了我的问题:

#include <cstdio>
#include <initializer_list>

struct base{
    virtual void foo() const = 0;
};

struct derived : public base{
    int i;
    derived(int i) : i(i) {}
    void foo() const{
        printf("bar %i", i);
    }
};

void foo_everything(const std::initializer_list<base> &list){
    for (auto i = list.begin(), iend = list.end(); i != iend; i++) i->foo();
}

int main(void){

    // Works fine
    derived d(0);
    base * base_ptr = &d;
    base_ptr->foo();    

    // Does not work fine
    foo_everything({ derived(1), derived(2), derived(3) });
}

请注意,在模板中使用 base& 会出错,因为 std::initializer_list 会尝试“[形成] 指向引用类型 base& 的指针”,并且在使用 base* 时,会获取每个对象的地址派生类实际上工作,它通过获取临时地址来实现,因此不安全(g++ 提示)。如果我在方法调用之外声明派生类(我的临时解决方案),后者确实有效,但它仍然比我希望的更冗长。

最佳答案

使用 initializer_list<base *> 的有点老套的方法:

template<class... Ts>
void foo_everything(Ts&&... args){
    std::initializer_list<base *> list = {&args...};
    for(auto i : list) i->foo();
}

然后从调用中移除大括号:

foo_everything(derived(1), derived(2), derived(3));

如果你真的不需要转换成base *并执行虚拟调用,只想调用 foo()在传入的每个对象上,然后我们可以使用通常的 pack-expansion-inside-an-initializer-list 技巧:

template<class... Ts>
void foo_everything(Ts&&... args){
    using expander = int[];
    (void) expander { 0, ((void) std::forward<Ts>(args).foo(), 0)...};
}

关于c++ - 作为 std::initializer_list 对象的抽象类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28659892/

相关文章:

c++ - MISRA C++(规则 18-4-1)和动态内存分配 - 是否允许 std::string?

c++ - 数组类型的模板参数推导

c++ - 使用 SFINAE 在 C++ 中强制类型转换

c++ - wchar的内容被删除

c++ - 移动后是否需要重置 std::list?

.net - 文件系统观察者

c++ - 令 ss 为 std::stringstream。如何指定 (ss<<some_type).str() 是 std::string 的概念?

C++:试图在类中封装 std::enable_if

c++ - 当我使用自定义分配器溢出 vector 时,为什么没有出现段错误?

c++ - 已弃用的 std::auto_ptr 的 c++11 标准等价物是什么?