2016-08-13 17 views
9

,如果我有一個模板:存儲和重新使用decltype值?

template <class T> 
struct Item 
{ 
    T _value; 
}; 

然後我就可以做:

// ... 
Item<int> x = { 42 }; // declared as an int 

// ... 
decltype(x._value) y = 20; // 'y' is also an int 

但有可能給decltype存儲到一個變量,這樣以後可以用嗎?

爲什麼?
我想存儲項目的值作爲指針。

喜歡的東西std::vector<Item*>而是以自己的模板,我必須將它們存儲爲指針void

std::vector<void*> is; 
is.push_back(new Item<int>()); 
is.push_back(new Item<double>()); 
is.push_back(new Item<float>()); 

而這一切,但是當談到時間刪除指針我需要重新鑄造我void*回到正確的類型(所以析構函數調用):

delete (Item<int>*)is[0]; 

如果我知道是什麼類型,我可以這樣做:

delete (Item<decltype(whatever)>*)is[0]; 

因此,我需要存儲decltype的原因。

我希望這是有道理的。

+2

你應該看看Boost.variant和Boost.any(或他們的C++ 17的同行['標準:: variant'(HTTP:// EN。 cppreference.com/w/cpp/utility/variant)和['std :: any'](http://en.cppreference.com/w/cpp/utility/any))。他們可能是你需要的更好的實現。 –

+0

類型擦除是關鍵字,在C中用'void *'完成,在C++中用'std :: any'和訪問者模式完成。智能指針解決方案實際上在內部使用某種類型的擦除。 – alfC

+0

@alfC請注意,類型刪除是在編譯時執行的,而訪問者模式背後的基本思想是雙重調度,即運行時機器。 – skypjack

回答

6

decltype是一種語言功能,允許您在編譯時檢索類型。您似乎希望「存儲」該類型,以便您可以在運行時正確地在動態存儲器上分配對象delete。假設是這樣,decltype在這裏不會有幫助。

你有多種選擇:

  1. 使用某種形式的類型擦除設備像Boost.VariantBoost.Any,如建議通過鮑姆麻省理工學院眼球中的註釋。

  2. 讓你的對象多態的層次結構的一部分,並使用智能指針:

    struct ItemBase 
    { 
        virtual ~ItemBase() { } 
    }; 
    
    template <class T> 
    struct Item : ItemBase 
    { 
        T _value; 
    }; 
    
    int main() 
    { 
        std::vector<std::unique_ptr<ItemBase>> items; 
        items.emplace_back(std::make_unique<Item<int>>()); 
        items.emplace_back(std::make_unique<Item<float>>());      
        items.emplace_back(std::make_unique<Item<double>>()); 
    } 
    
+1

@skypjack:好點,改進了答案。謝謝! –

+0

數字2是迄今爲止最簡單和最高效的。甚至可能有共享功能,最終ItemBase! – rubenvb

5

如果問題僅僅是刪除它們,你可以使用unique_ptr與定製刪除,而不是赤裸裸的指針。
您不需要修改您的層次結構來執行此操作。
作爲一個例子:

std::vector<std::unique_ptr<void, void(*)(void*)>> is; 
is.push_back(std::unique_ptr<void, void(*)(void*)>{new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); }}); 

更妙的是,如果使用emplace_back代替push_back

std::vector<std::unique_ptr<void, void(*)(void*)>> is; 
is.emplace_back(new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); }); 

它遵循基於業務方案的代碼最小,工作示例:

#include<vector> 
#include<memory> 

template<typename> 
struct Item {}; 

int main() { 
    using Deleter = void(*)(void*); 
    std::vector<std::unique_ptr<void, Deleter>> is; 
    is.emplace_back(new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); }); 
    is.emplace_back(new Item<double>(), [](void *ptr) { delete static_cast<Item<double>*>(ptr); }); 
    is.emplace_back(new Item<float>(), [](void *ptr) { delete static_cast<Item<float>*>(ptr); }); 
} 
+0

非常感謝,乾淨利落的做法。 –

1

你可能會存儲刪除者

所以用std::shared_ptr,就變成:

std::vector<std::shared_ptr<void>> items; 

// The simplest 
items.push_back(std::make_shared<Item<int>>(/*args...*/)); 

// Explicitly specify the (default) deleter 
items.push_back(std::shared_ptr<void>{new Item<double>(/*args...*/), 
             std::default_delete<Item<double>>{}}); 

// Explicitly specify the (default) allocator 
items.push_back(
    std::allocate_shared<Item<float>>(std::allocator<Item<float>>{} /*, args...*/);