2016-07-05 54 views
1

我想知道如果你可以有一個帶有不同模板參數的對象的容器。沒有模板參數的模板類的容器

我想實現這樣的事情:

#include <iostream> 
#include <list> 

template <class T> 
class base 
{ 
    public: 
     T val; 
     base(T newVal): val(newVal) {}; 
}; 

class derived : public base<int> 
{ 
    public: 
     derived(int newVal): base(newVal) {}; 
}; 

int main (void) 
{ 
    std::list < base<?> > base_collection; 
    return 0; 
} 

我想我目前的項目是靈活,動態地,很少有額外的編碼當一個新的派生類是必要的,而且我現在的實施使得這樣的清單存在很重要。

有沒有一個常用的,有益的和乾淨的方式來實現這一點?

+0

「我當前的實現使得這樣一個[異類]列表存在很重要」。哦。這是一種反模式。你需要拋棄這種設計。 –

+0

不,你不能。 '基地'是與*基地'完全不同的類型*。無論如何,你不能將派生類對象存儲在基類變量中。 – immibis

回答

2

一種可能的實現是使用雙調度

#include <iostream> 
#include <list> 

struct visitor; 

struct dispatchable { 
    virtual void accept(visitor &v) = 0; 
}; 

template <class> 
struct base; 

struct visitor { 
    template<typename T> 
    void visit(base<T> &); 
}; 

template <class T> 
struct base: dispatchable { 
    T val; 
    base(T newVal): val(newVal) {}; 
    void accept(visitor &v) override { v.visit(*this); } 
}; 

struct derivedInt : base<int> { 
    derivedInt(int newVal): base(newVal) {}; 
}; 

struct derivedDouble : base<double> { 
    derivedDouble(double newVal): base(newVal) {}; 
}; 

template<> 
void visitor::visit(base<int> &) { 
    std::cout << "int" << std::endl; 
} 

template<> 
void visitor::visit(base<double> &) { 
    std::cout << "double" << std::endl; 
} 

int main (void) { 
    visitor v{}; 
    std::list <dispatchable*> coll; 
    coll.push_back(new derivedInt{42}); 
    coll.push_back(new derivedDouble{.42}); 
    for(auto d: coll) d->accept(v); 
} 

這樣一來,你只需要定義特殊功能,與要引入新的base<T>類型的交易。
舉個例子,如果你想使用base<char>,你必須定義:

template<> 
void visitor::visit(base<char> &) { 
    std::cout << "char" << std::endl; 
} 

注意你要正確對待的base<T>各專門以不同的方式,我認爲。否則,定義通用成員函數visitor::visit並放棄特化就足夠了。


附註:不要使用裸指針。
這是一個例子。在生產代碼中,我會使用智能指針。

+0

這是完美的,非常感謝。 – reign

+0

只要每個類只有一個相關的操作,比如'process event',這是可以接受的。 –

+0

@JohanLundberg OP想要爲每個'T'處理'base ',沒有什麼更多。正如他在對你的回答的評論中提到的那樣,他*希望*使用'val'。這樣他可以使用它。在這種情況下雙調度很合適。究竟是什麼問題? – skypjack

3

這並不完全清楚你爲什麼需要這樣做,或者你打算對列表元素執行什麼操作(順便說一下,考慮使用std向量來代替)。我建議你做一個普​​通的非模板基類繼承的基礎來自:

struct mainbase { 
    virtual ~mainbase() = default; 
}; 

template <class T> 
class base : public mainbase 
{ 
    public: 
     T val; 
     base(T newVal): val(newVal) {}; 
}; 


class derived : public base<int> 
{ 
    public: 
     derived(int newVal): base(newVal) {}; 
}; 

int main (void) 
{ 
    std::list < std::unique_ptr<mainbase>> > base_collection; 
    return 0; 
} 

畢竟,如果你打算把他們都在一個載體,你最有可能需要一個共同的操作集,你可以用這些對象執行。把這些放在mainbase

正如@BenjaminLindley所指出的那樣,你不能有值多態。這就是爲什麼你會使用指針(such as unique_ptr)std::unique_ptr<mainbase>

使用C++ 17,有一個建議(正常軌道)std::any,可以用來代替,但是您仍然必須執行特定的強制轉換以獲取具有正確類型的內容。

+1

你會想要存儲指針(智能或其他)。 –

+0

如何在不投射的情況下從主體對象訪問val? – reign

+0

@BenjaminLindley。爲什麼在這種情況下使用指針? –

相關問題