#4020 closed Support Requests (fixed)
regex::match_results::format functor cannot use member variables
Reported by: | Owned by: | John Maddock | |
---|---|---|---|
Milestone: | Boost 1.43.0 | Component: | regex |
Version: | Boost 1.42.0 | Severity: | Problem |
Keywords: | regex functor | Cc: |
Description
regex::match_results::format makes a copy of its functor argument. This is restrictive, because it prevents the functor from managing its state using member variables. Is that intentional?
The attached VC++ 2008 code demonstrates the problem. When it uses a member variable to maintain a count, its output is:
(1)The (1)quick (1)brown (1)fox (1)jumped (1)over (1)the (1)lazy (1)dog
Making the counter global instead gives the correct output:
(1)The (2)quick (3)brown (4)fox (5)jumped (6)over (7)the (8)lazy (9)dog
Attachments (1)
Change History (5)
by , 13 years ago
Attachment: | RegexFunctor.zip added |
---|
comment:1 by , 13 years ago
comment:2 by , 13 years ago
As Steven says, this is the expected behaviour.
However, I will try and make that clearer in the docs, and I'll trivially update the code so that it works with boost::ref.
John.
comment:3 by , 13 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
comment:4 by , 13 years ago
Thanks for the clarification. Returning to C++ after a break, I had forgotten that it was a standard library convention to pass functors by value. Anyway, I've amended my example code to take account of that, and you're welcome to use it in the documentation:
// Code to insert an incremented count before each word in the source text. #include <stdlib.h> #include <iostream> #include <sstream> #include <boost/regex.hpp> #include <boost/shared_ptr.hpp> typedef wchar_t char_t; typedef std::wstring string_t; template <class M> class functor { public: functor() : m_pImpl(new functor_data) {} template <class O> O operator()(const M& m, O i) { // Generate the sequence number in brackets: char_t buf[16]; O i2(i); *i2++ = L'('; _itow(++m_pImpl->nCounter, buf, 10); i2 = std::copy(buf, buf + wcslen(buf), i2); *i2++ = L')'; // Copy the matched text; return m.format(i2, L"$0"); } private: struct functor_data { functor_data() : nCounter(0) {} int nCounter; }; boost::shared_ptr<functor_data> m_pImpl; }; int wmain(int argc, char_t* argv[]) { string_t sText(L"The quick brown fox jumped over the lazy dog"); string_t sRE(L"\\w+"); boost::regex_constants::match_flag_type matchFlags = boost::regex_constants::match_default; boost::basic_regex<char_t> e; e.assign(sRE, matchFlags); typedef string_t::const_iterator string_iterator; boost::regex_iterator<string_iterator> reit(sText.begin(), sText.end(), e, matchFlags); boost::regex_iterator<string_iterator> reEnd; boost::match_results<string_iterator> last_m = *reit; std::basic_ostringstream<char_t> stream; std::ostream_iterator<char_t, char_t> streamIter(stream); functor<boost::match_results<string_iterator> > func; for ( ; reit != reEnd; ++reit) { const boost::match_results<string_iterator>& m = *reit; // copy the source up to this match: std::copy(m.prefix().first, m.prefix().second, streamIter); // replace the matched text: m.format(streamIter, func); last_m = m; } // copy the remainder of the source string: std::copy(last_m.suffix().first, last_m.suffix().second, streamIter); // output the result: std::wcout << stream.str() << std::endl; return 0; }
This is normal behavior for interfaces that accept function objects. Put the variables outside the function object and store a pointer or reference to them.