2015-06-05 73 views
2

我正在嘗試做一些我認爲最初應該是微不足道的事情,但我遇到了設計問題,應該如何理想地構造它。我想創建一個存儲一堆參數的鍵值對的映射。這裏的「鑰匙」總是一個字符串。但是,該值可以是int,double,string或char。我有枚舉定義類型:C++中模板地圖的向量11

typedef enum {INT = 0, DOUBLE, STRING, CHAR} val_type; 

我想將其結構如地圖

std::vector<std::map<std::string, T>> params; 

什麼是最有原則的方式來進行此事的載體?

編輯:更新了矢量聲明。

+2

什麼是'矢量'的模板參數中的'int'應該是?你需要一個[Boost.Variants]的矢量(http://www.boost.org/doc/libs/release/doc/html/variant.html)。 – Praetorian

+0

糟糕,我犯了一個錯誤!它應該只是'std :: vector > params;' –

+0

所以,'boost :: variant'會解決你的問題嗎?您也可以編寫自己的類型安全標籤的聯合。另一個問題是,你打算如何使用這個向量的地圖'T'? – Yakk

回答

2

我有15分鐘。傳入標記的聯盟。不如boost::variant,我可能不會編譯它,但它應該讓你開始。

template<size_t S> 
using size = std::integral_constant<std::size_t, S>; 
template<bool b> 
using bool_t = std::integral_constant<bool, b>; 

template<size_t...Ss> 
struct max_size:size<0>{}; 
template<size_t S0, size_t...Ss> 
struct max_size:size<(std::max)(S0, max_size<Ss...>{}())>{}; 

template<class...Ts> 
struct max_alignof : max_size< alignof(Ts)... >{}; 
template<class...Ts> 
struct max_sizeof : max_size< sizeof(Ts)... >{}; 


template<class X>struct tag{using type=X;}; 
template<class...>struct types{using type=types;}; 
template<class Tag>using type_t=typename Tag::type; 

template<class T, class Types> 
struct index_of {}; 
template<class T, class...Ts> 
struct index_of<T, types<T,Ts...>>:size<0>{}; 
template<class T, class T0, class...Ts> 
struct index_of<T, types<T0,Ts...>>:size< 
    index_of<T, types<Ts...>>{}+1 
>{}; 

template<class X> 
struct emplace_as {}; 

template<class F, class...Ts> 
void invoke(types<Ts...>, void* p, F&& f, size_t i) { 
    auto* pf = std::addressof(f); 
    using operation=void(*)(decltype(pf), void*); 
    operation table[]={ 
    +[](decltype(pf), void* p){ 
     Ts* pt = static_cast<Ts*>(p); 
     std::forward<F>(*pf)(*pt); 
    }... 
    }; 
    table[i](pf, p); 
} 

template<class T0, class...Ts> 
struct one_of { 
    std::aligned_storage< max_sizeof<T0, Ts...>{}, max_alignof<T0, Ts...>{} > data; 
    size_t index = -1; 
    using my_types = types<T0, Ts...>; 
    template<class T> 
    using sfinae_my_type = tag< size<index_of<X,my_types>{}> >; 

    one_of():one_of(emplace_as<T0>{}) {} 

    // brace construction support for only the first type: 
    one_of(T0&&t0):one_of(emplace_as<T0>{}, std::move(t0)) {} 

    template<class X, class...Args, class=sfinae_my_type<X>> 
    one_of(emplace_as<X>, Args&&... args){ 
    emplace(emplace_as<X>{}, std::forward<Args>(args)...); 
    } 
    template<class X, class=sfinae_my_type<std::decay_t<X>>> 
    one_of(X&& x) { 
    emplace_as(std::forward<X>(x)); 
    } 
    template<class X, class=sfinae_my_type<X>> 
    X* get() { 
    if (index_of<X, my_types>{}==index) { 
     return static_cast<X*>(&data); 
    } else { 
     return nullptr; 
    } 
    } 
    template<class X, class=sfinae_my_type<X>> 
    X const* get() const { 
    if (index_of<X, my_types>{}==index) { 
     return static_cast<X const*>(&data); 
    } else { 
     return nullptr; 
    } 
    } 

    template<class X, class=sfinae_my_type<std::decay_t<X>>> 
    void emplace(X&& x) { 
    emplace_as<std::decay_t<X>>{}, std::forward<X>(x)); 
    } 

    template<class X, class...Args, class=sfinae_my_type<X>> 
    void emplace(emplace_as<X>, Args&&...args) { 
    destroy(); 
    new(&data) X(std::forward<Args>(args)...); 
    index = index_of<X, list<T0, Ts...>>{}; 
    } 

    template<class F> 
    void my_invoke(F&& f) { 
    my_invoke(std::forward<F>(f), index); 
    } 
    template<class F> 
    void apply(F&& f) { 
    invoke(my_types{}, &data, std::forward<F>(f), index); 
    } 
    void destroy() { 
    if (index != -1) { 
     apply([&](auto&& x){ 
     using X=std::decay_t<decltype(x)>; 
     index = -1; 
     x.~X(); 
     }); 
    }; 
    } 

    one_of& operator=(one_of const& rhs){ 
    if (this == &rhs) return *this; 
    destroy(); 
    rhs.apply([&](auto const& x) { 
     using X=std::decay_t<decltype(x)>; 
     emplace(emplace_as<X>{}, decltype(x)(x)); 
    }); 
    return *this; 
    } 
    one_of& operator=(one_of&& rhs){ 
    if (this == &rhs) return *this; 
    destroy(); 
    rhs.apply([&](auto & x) { 
     using X=std::decay_t<decltype(x)>; 
     emplace(emplace_as<X>{}, std::move(x)); 
    }); 
    return *this; 
    } 
    ~one_of(){destroy();} 
}; 

這是一個標記聯合類型的快速草圖。

店面a one_of<int, double, std::string, char>作爲您的T。通過apply傳遞一個覆蓋每個函數的函數或get<T>

上面是C++ 14,因爲它使它更容易。它不包括具有返回值的apply,因爲它使得它更容易。兩者都可以彌補,但它需要工作,而且真的,你應該看看如何boost而不是使用上述。