#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.