2011-04-17 92 views
11

我有一个菜单系统,我想从常量数据初始化。 A MenuItem可以包含作为子菜单的MenuItems的矢量。但它只起到一个作用。这是问题的梗概:初始化一个包含自身向量的结构

#include <vector> 
struct S { std::vector<S> v ; } ; 

S s1 = { } ; 
S s2 = { { } } ; 
S s3 = { { { } } } ; 

g++ -std=c++0x(4.4.5版本)与s1s2科佩斯,但s3回来了:

prog.cpp:6:22: error: template argument 1 is invalid 

(见ideone)。难道我做错了什么?

+4

这是不确定的行为有一个不完整的类型作为模板参数为标准库容器。 – GManNickG 2011-04-17 05:48:37

+5

有关更多信息,请参见Matt Austern的[“标准馆员:不完整类型的容器”](http://drdobbs.com/184403814) – 2011-04-17 05:56:34

回答

11

GMan在他的评论中是正确的:在您的代码中S::v的声明中,S仍然不完整。一个类型必须完整才能用作STL容器中的值类型。欲了解更多信息,请参阅马特奥斯汀的文章"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*/ } } } } } } } } } } } } } } } }; 
+0

该文章的+1,这是一个很好的阅读。 – Xeo 2011-04-17 06:23:23

+0

这难道不是过于简单到荒谬的地步吗?这不是“一个包含自身向量的结构体”,而且您还没有“切换到允许不完整类型的容器”......因为它们都不包含任何数据!此代码不存储任何内容,并且什么都不做在我看来,它与价值的“包含自己的物体”的不可能性完美地平行。 – 2016-07-17 08:00:55

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; 
} 

您使用的代码看起来不合适。如果要实现包含结构(树)的结构,请在节点中包含指向结构/节点的指针列表(或者只是指向无法实现的无效指针)。

大多数菜单结构本质上是一个有序的基于列表的树(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; 
     } 
}; 

问题是这里相互依赖,我想我已经用类声明解决了它。 做class CTreeNode;课前CTree {}。 http://www.codeguru.com/forum/showthread.php?t=383253

我可能会弄坏这段代码,但它不完整,因为我没有多年需要编写一棵树,但我想我已经介绍了基本知识。我没有实现operator []。

+2

'std :: initialize_list <>'与库特征一样是一种语言特性,因此不能成为技术报告的一部分(即仅为C++ 0x的一部分)。 – ildjarn 2011-04-18 03:01:38

6

的boost ::可选和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" } 
    } 
};