我是從你的要求是什麼稍有不同的實現,但也許它會爲工作您。我做了一個類似列表的結構,當你試圖向其中添加一個新類型的元素時,它可以複製或移動到一個可以包含該新元素類型的封裝容器(不同類型)中。 (就像副本中的持久數據結構一樣)。
這是代碼。這是非常醜陋的,我不會發布它,但在撰寫本文時沒有回答,所以我只能希望有人能幫助它變得更好。
//Checks if list (or element) S has element of type T
template<class L, class T> struct HasElem : std::is_same<L,T>{};
template<template<class,class> class Node, class T, class NodeT, class Next>
struct HasElem<Node<NodeT,Next>,T>{
static constexpr bool value = std::is_same<NodeT,T>::value || HasElem<Next,T>::value;
};
template<template<class> class Leaf, class S, class T> struct HasElem<Leaf<S>,T> : std::is_same<S,T>{};
//Push type transform
template<class N, class T> struct Push{};
template<template<class,class> class Node, class T, class Next, class U> struct Push<Node<T,Next>,U>{
typedef Node<U,Node<T,Next>> type;
};
//Node type
template<class T, class Next>
struct Node{
Node(Next&& nxt) : next(nxt){}
Node(const Next& nxt) : next(nxt){}
std::stack<T> st;
Next next;
//Pushing a new type onto the stack
template<class U> typename std::enable_if<!HasElem<Node,U>::value,typename Push<Node,U>::type>::type
push(const U& u) &&{ //disallow pushing new types on lvalues
return typename Push<Node,U>::type(std::move(*this)).push(u);
}
//Pushing a new type onto the stack as an lvalue and return a copy
template<class U> typename std::enable_if<!HasElem<Node,U>::value,typename Push<Node,U>::type>::type
push_new(const U& u) const{ //cannot overload on && qualifier. Make the name uglier to warn of the cost
return typename Push<Node,U>::type(*this).push(u);
}
//Regular old push
Node& push(const T& t){ st.push(t); return *this; }
//Push onto another node in the list
template<class U> typename std::enable_if<HasElem<Node,U>::value,Node>::type
push(const U& u){ next.push(u); return *this; }
template<class U> typename std::enable_if<std::is_same<T,U>::value,U>::type&
top(){ return st.top(); }
template<class U> typename std::enable_if<!std::is_same<T,U>::value && HasElem<Node,U>::value,U>::type&
top(){ return next.top<U>(); }
};
//The last node. I made it hold data but it doesn't need to
template<class T> struct Leaf{
std::stack<T> st;
Leaf& push(const T& t){ st.push(t); return *this; }
template<class U> Node<U,Leaf> push(const U& u){
return Node<U,Leaf>(std::move(*this)).push(u);
}
template<class U> void top(){}
T& top(){ return st.top(); }
void pop(){ st.pop(); }
};
下面是如何使用它,躲遠push
和push_new
之間的差別的例子。
template<class T, class Next, class U> auto push(Node<T,Next>&& n, const U& u)
-> decltype(n.push(u)){
return n.push(u);
}
template<class T, class Next, class U> auto push(const Node<T,Next>& n, const U& u)
-> decltype(n.push_new(u)){
return n.push_new(u);
}
int main(){
auto b = Leaf<int>().push<int>(42).push<double>(3.14).push<char>('a');
auto a = push(b,(char*)"Hello"); //Make a copy of b but with "Hello"
cout << a.top<int>() << " " << a.top<double>() << " " <<
a.top<char>() << " " << a.top<char*>() << endl;
cout << b.top<char>() << endl; //The earlier version b still exists
}
的主要缺點是,如果在保存的中間狀態將是低效率的(即入變量),但如果在例如鏈運作在一起像b
可以避開它。
您不能根據任何隨機客戶端可能*以後使用類型來定義類型。如果沒有某種動態代碼,你不能建立一個無界的數據結構。 –
正如你展示你的_'nive實現',可能是[這個問答'從元組或變量模板參數創建數組初始化'](http://stackoverflow.com/questions/18251815/creating- an-array-initializer-from-a-tuple-or-variadic-template-parameters)對你很有用。我相信你的用例可能是相似的。至少我需要這樣來定義某些閃存數據佈局(併成功使用了這個習慣用法)。 –
'boost :: any'是新的'void *'。 –