Search code examples
c++boostboost-spiritboost-spirit-qi

Searching/Iterating boost::spirit::qi::symbols


If I have a symbol table:

struct MySymbols : symbols<char, MyEnum::Fruits>
{
    MySymbols ()
        : symbols<char, MyEnum::Fruits>(std::string("MySymbols"))
    {
        add("apple", MyEnum::Apple)
           ("orange", MyEnum::Orange);
    }
};

I want to iterate over the table in order to search for a symbol by data value. I cannot use lambda expressions so I implemented a simple class:

template<typename T>
struct SymbolSearcher
{
    SymbolSearcher::SymbolSearcher(T searchFor)
        : _sought(searchFor)
    {
        // do nothing
    }

    void operator() (std::basic_string<char> s, T ct)
    {
        if (_sought == ct)
        {
            _found = s;
        }
    }

    std::string found() const { return _found; }

private:
    T _sought;
    std::string _found;
};

And I'm using it as follows:

SymbolSearcher<MyEnum::Fruits> search(ct);
MySymbols symbols;

symbols.for_each(search);
std::string symbolStr = search.found();

If I set a breakpoint on _found = s I can confirm that _found is getting set, however search.found() always returns an empty string. I'm guessing it has something to do with the way the functor is being called inside for_each but I don't know.

What am I doing wrong?


Solution

  • It could be that

    • the actual value of the string is the empty string (unlikely)

    • the functor is being passed by value, making the stateful functor useless (as the original state will not actually be passed).

    You could make the _found field a reference (requiring you to make sure to respect the Rule-Of-Three to make it work).

    Here's a demonstration that shows the principle by asserting the result of a roundtrip via SymbolSearcher: http://liveworkspace.org/code/4qupWC$1

    #include <boost/spirit/include/qi.hpp>
    
    namespace qi     = boost::spirit::qi;
    
    template<typename T>
    struct SymbolSearcher
    {
        SymbolSearcher(T searchFor, std::string& result) : _sought(searchFor), _found(result)
        {
        }
    
        void operator() (std::basic_string<char> s, T ct)
        {
            if (_sought == ct)
            {
                _found = s;
            }
        }
    
        std::string found() const { return _found; }
    
    private:
        T _sought;
        std::string& _found;
    };
    
    int main()
    {
        const std::string str("mies");
    
        typedef std::string::const_iterator It;
        It begin = str.cbegin();
        It end   = str.cend();
    
        qi::symbols<char, int> symbols;
        symbols.add("aap", 1)("noot", 2)("mies", 3);
    
        int out;
        bool ok = qi::parse(begin, end, symbols, out);
        assert(ok);
    
        std::string found;
        SymbolSearcher<int> sf(out, found);
        symbols.for_each(sf);
    
        assert(str == sf.found());
    }