2016-06-05 7 views
4

Ich kann std :: remove_if nicht kompilieren, wie Sie sehen können Ich wählte eine alternative Handkurbel-Methode, die gut funktioniert, die Compilerfehler sind am Ende der Auflistung nach dem Code.STL std :: remove_if Compiler Fehler

Jede Hilfe würde sehr geschätzt werden.

Danke, Tom

#include <iostream> 
#include <fstream> 
#include <set> 
#include <algorithm> 
#include <string> 

// 
// Find the largest compound word composed 
// of sub-words from a list. 
// 
// - read list from file. 
// 
// Psuedo Code: 
// 
// 1. Read Next Word from File. 
// 2. Search in list for word formed from word. 
// 3. if Found in List 
// 4. if Found Compound is longer then Current Compound 
// 5.  Replace 
// 6.  Remove all strings less then Current Compound Length 
// 7. 
// 

typedef std::set<std::string> StrSet; 
typedef StrSet::iterator StrSetIter; 


struct if_substr 
{ 
    std::string m_word; 
public: 
    if_substr(const std::string& w) : m_word(w) { } 

    bool operator() (const std::string& str) const 
    { 
    std::size_t f = m_word.find(str); 
    return (std::string::npos!=f && m_word.length()>str.length()); 
    } 

}; 

struct if_remove 
{ 
    std::string m_word; 
public: 
    if_remove(const std::string& w) : m_word(w) { } 

    bool operator() (std::string str) const 
    { 
     return m_word.length()>str.length(); 
    } 

}; 


class FindLongestCompound 
{ 

    std::ifstream m_file; 

    StrSet m_words; 
    std::string m_current; 

public: 
    FindLongestCompound(std::string filename) 
    { 
    m_file.open(filename, std::ifstream::in); 

    if (!m_file) 
     throw std::runtime_error("Failed to open file"+filename); 
    } 


    void Start(void) 
    { 
    std::string nextWord; 
    while(m_file >> nextWord) 
    { 

     std::cout << "read word: " << nextWord << std::endl; 
     if_substr ifSubstr(nextWord); 
     StrSetIter srchItem = std::find_if(std::begin(m_words), std::end(m_words),ifSubstr); 
     if (srchItem != m_words.end()) 
     { 
     m_current = nextWord; 
     std::cout << "new current: " << m_current << std::endl; 


     if_remove ifRemove(m_current); 
     std::remove_if(m_words.begin(), m_words.end(),ifRemove); 

     #if 0 
     StrSetIter j = m_words.begin(); 
     do 
     { 
      if (j->length() < m_current.length()) 
      j = m_words.erase(j); 
      else 
      j++; 

     } while (j != m_words.end()); 
     #endif 
     } 
     std::cout << "insert next word: " << nextWord << std::endl; 
     m_words.insert(nextWord); 
    } 
    } 

    std::string result() { return m_current; } 

}; 


int main(int argc, char *argv[]) 
{ 
    if (argc<2) 
    { 
    std::cout << "Please provide filename" << std::endl; 
    return -1; 
    } 

    FindLongestCompound flc(argv[1]); 

    flc.Start(); 

    std::cout << "result: " << flc.result() << std::endl; 
} 
--- errors --- 
In file included from stackoverflow.C:2: 
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iostream:38: 
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ios:216: 
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__locale:15: 
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:439: 
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:2148:26: 
error: no viable overloaded '=' 
        *__first = _VSTD::move(*__i); 
        ~~~~~~~~^~~~~~~~~~~~~~~~~~ 
    stackoverflow.C:91:8: note: in instantiation of function template specialization 
'std::__1::remove_if<std::__1::__tree_const_iterator<std::__1::basic_string<char>, 
std::__1::__tree_node<std::__1::basic_string<char>, void *> *, long>, 
if_remove>' requested here 
        std::remove_if(m_words.begin(), m_words.end(),ifRemove); 
         ^
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1415:19: 
note: candidate function not viable: 'this' argument has type 'const 
value_type' (aka 'const std::__1::basic_string<char>'), but method is 
not marked const 
     basic_string& operator=(const basic_string& __str); 
        ^
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1422:45: 
note: candidate function not viable: 'this' argument has type 'const 
value_type' (aka 'const std::__1::basic_string<char>'), but method is 
not marked const 
     _LIBCPP_INLINE_VISIBILITY basic_string& operator=(const value_type* __s) {return assign(__s);} 
               ^
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1423:19: 
note: candidate function not viable: 'this' argument has type 'const 
value_type' (aka 'const std::__1::basic_string<char>'), but method is 
not marked const 
     basic_string& operator=(value_type __c); 
        ^
    1 error generated. 
+2

Grenzen Sie Ihr Problem ein. –

+1

Versuchen Sie, ein [*** minimales ***, vollständiges und verifizierbares Beispiel] (http://stackoverflow.com/help/mcve) zu erstellen. –

+1

Auch, wenn Sie mit C++ 11 programmieren, warum verwenden Sie Funktor-Objekte anstelle von Lambda? –

Antwort

6

Das Problem ist nicht mit Ihrem Funktors aber mit dem Containertyp Sie verwenden. Sie können std::remove_if nicht mit einer std::set (Ihre StrSet in diesem Fall) verwenden.

Einfach ausgedrückt, entfernt std::remove_if nichts als nur ändert die Reihenfolge der Elemente so, dass die "entfernten" Elemente erst nach einem bestimmten Punkt angezeigt werden. Nur erase beseitigt sie wirklich.

Eine std::set hat jedoch eine definierte Elementreihenfolge, die von keiner Operation umgangen werden kann. Angenommen, Sie haben die von lexikographisch geordnet Strings gesetzt folgende:

{ "aaa", "bbb", "ccc", "ddd", "eee" } 

Jetzt versuchen Sie std::remove_if mit einem Funktor anzuwenden, die alle Vokal-nur Strings entfernt. Sie würden damit enden:

{ "bbb", "ccc", "ddd", "aaa", "eee" } 
        ^
        | 
     "removed" elements start here 

Dies funktioniert mit z. std::vector, aber nicht mit std::set, weil dies zu einem Satz führen würde, dessen Elemente nicht mehr korrekt geordnet sind (die "entfernten" Elemente sind immer noch Teil des Sets!). Sie erhalten also einen Kompilierungsfehler.

Um das gewünschte Ziel zu erreichen, verwenden Sie std::set::erase in einer Schleife. Es funktioniert gut, da nur Iteratoren für das gelöschte Element ungültig sind, so dass end() weiterhin gültig bleibt.

if_remove ifRemove(m_current); 
for (StrSet::iterator set_iter = m_words.begin(); set_iter != m_words.end();) 
{ 
    if (ifRemove(*set_iter)) 
    { 
     set_iter = m_words.erase(set_iter); 
    } 
    else 
    { 
     ++set_iter; 
    } 
} 

In C++ 11, könnten Sie auto statt StrSet::iterator verwenden.