簡體   English   中英

抽象類作為std :: initializer_list對象

[英]Abstract class as std::initializer_list object

為了獲得更清晰的語法,我想使用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&in模板錯誤,因為std :: initializer_list嘗試“ [form a]指向引用類型base& ”,並且在使用base *時,然后獲取每個派生類的地址實際上工作,它確實所以通過取得臨時的地址,因此是不安全的(g ++抱怨)。 如果我在方法調用之外聲明派生類(我的臨時解決方案),后者確實有效,但它仍然比我希望的更冗長。

使用initializer_list<base *>一些hackish方法:

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)...};
}

如果你想要語法

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

要工作,你必須使用模板。 例如,

template<typename T>
void foo_everything(std::initializer_list<T> list)
{
  for(const auto&x:list) x.foo();
}

您可以添加一些SFINAE魔法以確保T來自基數:

template<typename T>
typename std::enable_if<is_base_of<base,T>::value>::type
foo_everything(std::initializer_list<T> list)
{
  for(const auto&x:list) x.foo();
}

如果要在一次調用foo_everything使用不同的派生類 ,則無法使用首選語法

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

(句號)這只是因為std::initializer_list包裝了一個數組,並且數組必須具有相同類型的對象。 因此,從嚴格意義上說,答案很簡單:無法做到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM