2012-11-13 49 views
1

我有以下功能,无法弄清楚它为什么不起作用。为什么我的std :: set find()不起作用?

参数是一组非终结符和一个GrammarSymbol *(一个词)的向量。非终结符是GrammarSymbol的一个子类。该函数应该过滤包含在单词以及非终结集中的所有非终结符,并将它们返回到一个集合中。

std::set<Nonterminal> Filter(const std::set<Nonterminal>& symbolSet, const std::vector<GrammarSymbol*> w){ 

    //resulting set 
    std::set<Nonterminal> rSet; 

    std::vector<GrammarSymbol*>::const_iterator wit; 
    std::set<Nonterminal>::const_iterator ntit; 

    //iterate over all symbols of the word 
    for(wit = w.begin(); wit != w.end(); wit++){ 

    //test if current symbol is a nonterminal 
    const Nonterminal* nt = dynamic_cast<const Nonterminal*>(*wit); 
    if(nt != NULL){ 
     std::cout << "current symbol " << nt->Str() << " is nonterminal" << std::endl; 

     for(ntit = symbolSet.begin(); ntit != symbolSet.end(); ntit++){ 
     std::cout << ntit->Str() << " " << (!(*ntit < *nt) && !(*nt < *ntit))<< std::endl; 
     } 
     //look for the symbol in the nonterminal set 
     ntit = symbolSet.find(*nt); 

     //if the symbol was found, insert it into resulting set 
     if(ntit != symbolSet.end()){ 
     rSet.insert(*ntit); 
     std::cout << "inserted " << ntit->Str() << "into set, size: " << rSet.size() << std::endl; 
     } 
     else{ 
     std::cout << "not found in symbolSet" << std::endl; 
     } 
    } 
    } 
    return rSet; 
} 

这就产生输出

current symbol (1, 2, 2) is nonterminal 
(1, 2, 2) 1 
(2, 3, 3) 0 
(3, 2) 0 
(4, 3) 0 
(5, 3, 1) 0 
not found in symbolSet 

如果我不依靠过滤功能,过滤器对我自己只是正常工作:

std::set<Nonterminal> Filter(const std::set<Nonterminal>& symbolSet, const std::vector<GrammarSymbol*> w){ 

    //resulting set 
    std::set<Nonterminal> rSet; 

    std::vector<GrammarSymbol*>::const_iterator wit; 
    std::set<Nonterminal>::const_iterator ntit; 

    //iterate over all symbols of the word 
    for(wit = w.begin(); wit != w.end(); wit++){ 

    //test if current symbol is a nonterminal 
    const Nonterminal* nt = dynamic_cast<const Nonterminal*>(*wit); 
    if(nt != NULL){ 
     std::cout << "current symbol " << nt->Str() << " is nonterminal" << std::endl; 

     for(ntit = symbolSet.begin(); ntit != symbolSet.end(); ntit++){ 
     std::cout << ntit->Str() << " " << (!(*ntit < *nt) && !(*nt < *ntit))<< std::endl; 
     if(!(*ntit < *nt) && !(*nt < *ntit)){ 
      rSet.insert(*ntit); 
     } 
     } 
    } 
    } 
    return rSet; 
} 

谁能给我解释一下这里发生了什么?据我所知,std :: set应该将元素与运算符<进行比较。如输出所示,比较似乎工作得很好。

我会继续使用自制过滤器,但我担心会有更大的潜在问题。

谢谢!

编辑:非终结和运营商<对非终结:

class Nonterminal : public GrammarSymbol{ 

    public: 

    /** The start state*/ 
    Idx mStartState; 
    /** The stack symbol*/ 
    Idx mOnStack; 
    /** The end state */ 
    Idx mEndState; 
    //... 
    } 

IDX仅仅是一个int的类型定义。

bool Nonterminal::operator<(const GrammarSymbol& other) const{ 
    if(typeid(*this) != typeid(other)) return true; //other is a terminal 
    const Nonterminal& nt = dynamic_cast<const Nonterminal&>(other); //other is a nonterminal 
    if (mStartState < nt.StartState()) return true; 
    if (mOnStack < nt.OnStack()) return true; 
    if (mEndState < nt.EndState()) return true; 
    return false;  
} 
+1

你可以显示你的'Nonterminal :: operator <'做什么? – Benj

+0

我已添加它。 – Shal

回答

3

operator <是不正确

考虑

Nonterminal nt1 (1,2,3); 
Nonterminal nt2 (3,2,1); 

bool b1 = nt1 < nt2; 
bool b2 = nt2 < nt1; 

nt1 < nt2比较:

  • 1 < 3 immediatelly yelds true;

对于nt2 < nt1

  • 3 < 1不成立,所以你继续
  • 2 < 2这不成立,所以你继续
  • 1 < 3持有

因此b1b2将是true,这完全是无稽之谈

至于你的filter秒变种,它的工作原理becase的逻辑错误

for(ntit = symbolSet.begin(); ntit != symbolSet.end(); ntit++){ 
     std::cout << ntit->Str() << " " << (!(*ntit < *nt) && !(*nt < *ntit))<< std::endl; 
     if(!(*ntit < *nt) && !(*nt < *ntit)){ 
      rSet.insert(*ntit); 
     } 

这里rSet.insert(*ntit);都会被调用一次if(!(*ntit < *nt) && !(*nt < *ntit))不成立,没有一次因为它应该。

+0

否。如果两个非终结符比较,则只比较三个整数。 'if(typeid(* this)!= typeid(other))返回true;'只有当我比较非终结符和终端时才会调用它(参见回答Benj的回答)。在你的例子中,因为'1 <3'和'b2 = false',因为'3!<1','b1 = true'会保持不变。 – Shal

+0

@Shal,对于'nt1 2012-11-13 12:26:19

+0

你说得对。道歉反驳它。 =)谢谢,我需要拿出一个更好的比较。 – Shal

相关问题