【发布时间】:2015-02-22 15:56:18
【问题描述】:
为了获得更简洁的语法,我想使用 std::initializer_list 将对象列表发送到构造函数。然而,这些对象是抽象的,这会导致一个问题:在 VS 2013 中,它丢失了 vfptr 引用,给出了“R6025:纯虚函数调用”运行时错误,并且在 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 会尝试“[form a] pointer to reference type base&”,并且在使用 base* 时,然后获取每个的地址派生类确实有效,它通过获取临时地址来实现,因此不安全(g++ 抱怨)。如果我在方法调用之外声明派生类(我的临时解决方案),后者确实有效,但它仍然比我希望的更冗长。
【问题讨论】:
-
一个
std::initializer_list<base>商店,嗯,bases。使用可变参数模板。 -
或者使用指针(这在你的情况下会很棘手)。
-
广告
const std::initializer_list<base> &:initializer_list<T>类具有指针语义,因此无需通过引用传递它们。 -
潜在的问题是,这是试图将
derived的array 传递到derived的大小未知的某些上下文。将一组指针传递给derived是可能的,即使这些指针包含临时地址:initializer_list本身的生命周期已经存在问题,因此恕我直言,这并不是真正危险得多。 -
我不确定,但如果标准允许
std::initializer_list<abstract_class>,我会感到非常惊讶。毕竟,initializer_list<T>是数组的轻量级包装器,抽象类型的数组是不可能的。