我有一个菜单系统,我想从常量数据初始化。 MenuItem
可以包含MenuItems
的向量作为子菜单。但它只能达到一定程度。以下是问题的基础:
#include <vector>
struct S { std::vector<S> v ; } ;
S s1 = { } ;
S s2 = { { } } ;
S s3 = { { { } } } ;
g++ -std=c++0x
(版本4.4.5)处理s1
和s2
,但s3
回复:
prog.cpp:6:22: error: template argument 1 is invalid
(见ideone)。我做错了吗?
答案 0 :(得分:11)
GMan的评论是正确的:在您的代码S::v
声明中,S
仍然不完整。必须完整的类型才能用作STL容器中的值类型。有关更多信息,请参阅Matt Austern的文章"The Standard Librarian: Containers of Incomplete Types."
如果您要切换到可用于不完整类型的容器,那么您的代码就可以了。例如,给出以下内容:
#include <initializer_list>
template <typename T>
struct Container
{
Container() { }
Container(std::initializer_list<T>) { }
};
struct S { Container<S> v; };
然后您的原始初始化应该可以正常工作:
S s3 = { { { } } } ;
这也可行:
S s4 = { { { { { { { { { { { { { { { { /*zomg*/ } } } } } } } } } } } } } } } };
答案 1 :(得分:6)
boost :: optional和boost :: recursive_wrapper对于这个
看起来很有用struct S { // one brace
boost::optional< // another brace
boost::recursive_wrapper< // another brace
std::vector< // another brace
S
>
>
> v;
};
您添加的每个子菜单都需要4个大括号。涉及构造函数调用时,不会发生Brace elision。例如
S m{{{{
{{{{ }}}},
{{{{
{{{{ }}}},
{{{{ }}}}
}}}}
}}}};
老实说,使用构造函数看起来更具可读性
struct S {
// this one is not really required by C++0x, but some GCC versions
// require it.
S(char const *s)
:v(s) { }
S(std::string const& s)
:v(s) { }
S(std::initialize_list<S> s)
:v(std::vector<S>(s)) { }
boost::variant<
std::string,
boost::recursive_wrapper<
std::vector<
S
>
>
> v;
};
现在它简化为
S s{
"S1",
{
"SS1",
"SS2",
{ "SSS1", "SSS2" }
}
};
答案 2 :(得分:0)
你要做的是一个名为“初始化列表”的即将发布的当前C ++特性,其中一个向量或列表可以用= {}初始化。
我不知道他们是否已经在TR1中推出了它。也许它在TR2。
#include <vector>
#include <list>
#include <iostream>
using namespace std;
int main(void) {
vector<int> vi = {1, 2, 3, 4, 5};
list<int> li = {5, 4, 3, 2, 1, 0};
cout<<"vector size="<<vi.size()<<", list size="<<li.size()<<endl;
return 0;
}
您使用的代码对我来说不合适。如果要实现包含结构(树)的结构,请在节点内包含指向结构/节点的指针列表(或者只有在无法实现的情况下使用void指针)。
大多数菜单结构本质上是一个有序的基于列表的树(一个地方有n个节点,但在其他地方可能是m个节点,等等)。 Robert Sedgewick制作了一本教科书“C ++中的算法”。
#include <vector>
#include <iterator>
#include <string>
void * pRoot = NULL; //pointer to CTree
class CTreenode;
class CTree;
class CTree {
public:
vector<class CTreeNode> lctnNodeList; //list does not have at() or operator[]
vector<class CTreeNode>::iterator lctni;
public:
CTree() {}
~CTree() {
for (lctni=lctnNodeList.begin(); lctni != lctnNodeList.end(); nctni++) {
if (NULL==lctni->getChildPtr()) {
//do nothing, we have already done all we can
} else {
delete (CTree *)lctnNodeList.pChild;
}
//do action here
}
}
void addToList(string& data, CTree * p) {
CTreeNode ctn(data, p);
lctnNodeList.push_back(d);
}
void eraseAt(size_t index) {
vector<class CTreeNode>::iterator i = lctnNodeList.begin();
vector<class CTreeNode>::iterator i2 = lctnNodeList.begin();
i2++;
size_t x;
for (x=0; x <= index; x++,i++,i2++) {
if (index == x) {
lctnNodeList.erase(i,i2);
break;
}
}
}
void at(size_t index, string& returndata, CTree * &p) {
vector<class CTreeNode>::iterator i = lctnNodeList.begin();
size_t x;
for (x=0; x <= index; i++,x++) {
if (x==index) {
i->getData(returndata, p);
break;
}
}
}
const CTreeNode& operator[](const size_t idx) {
if (idx < lctnNodeList(size)) {
return lctnNodeList.at(idx);
} else {
//throw an error
}
}
const size() {
return lctnNodeList.size();
}
//this can be applied to the root of the tree (pRoot).
doActionToThisSubtree(void * root) {
CTree * pct = (CTree *)root;
for (pct->lctni=pct->lctnNodeList.begin(); pct->lctni != pct->lctnNodeList.end(); pct->nctni++) {
//this is a depth-first traversal.
if (NULL==pct->lctni->getChildPtr()) {
//do nothing, we have already done all we can
//we do this if statement to prevent infinite recursion
} else {
//at this point, recursively entering child domain
doActionToThisSubtree(pct->lctni->getChildPtr());
//at thisd point, exiting child domain
}
//do Action on CTreeNode node pct->lctni-> here.
}
}
};
class CTreeNode {
public:
CTree * pChild; //CTree *, may have to replace with void *
string sData;
public:
CTreeNode() : pChild(NULL) {}
CTreeNode(string& data, pchild) : pChild(pchild) {
sData = data;
}
~CTreeNode() {
if (NULL!=pChild) {
delete pChild;//delete (CTree *)pChild;
pChild = NULL;
}
void getChild(CTreeNode& child) {
child = *pChild;//child = *((CTree *)pChild);
}
bool addChild(string& s) {
if (NULL==pChild) {
return false;
} else {
pChild = new CTree;
}
return true;
}
void * getChildPtr() { return pChild; }
void getData(string& data, CTree * &p) { //not sure about how to put the & in there on CTree
data=sData;
p = pChild;
}
void setData(string& data, CTree * p) {
sData=data;
pChild = p;
}
};
这里的问题是相互依赖,我想我已经用类声明解决了。 做类CTreeNode;在课前CTree {}。 http://www.codeguru.com/forum/showthread.php?t=383253
我可能会破坏这段代码,而且它不完整,因为我多年来没有必要写一棵树,但我想我已经涵盖了基础知识。我没有实现operator []。