Opened 9 years ago

Closed 8 years ago

#9851 closed Bugs (fixed)

Iterators from rang have different category than the range

Reported by: anonymous Owned by: Neil Groves
Milestone: Boost 1.56.0 Component: range
Version: Boost 1.55.0 Severity: Problem
Keywords: Cc:

Description

According to the documentation for transformed, the category is single pass, which means that it should be safe to include side effects in the function used:

int main() {
	int transformed_called = 0, filtered_called = 0;
	vector<int> a{ 1, 2, 3 };
	auto b = (a | transformed([&](int aa) {
		++transformed_called;
		return aa + 1;
	}) | filtered([&](int aa) {
		++filtered_called;
		return aa < 4;
	}));
	auto c = vector<int>(b::begin(b), b::end(b));
	cout << transformed_called << ", " << filtered_called << endl;
	return 0;
}

However, the output of this program is "5, 3" instead of the expected "3, 3", which means that the iterators returned by begin() and end() are forward iterators. I guess they should be input iterators (single pass) instead?

Change History (9)

comment:1 by anonymous, 9 years ago

Strangely, removing the line

auto c = vector<int>(b::begin(b), b::end(b));

results in the output "1, 1" instead of "0, 0", so it seems like merely chaining together adaptors causes the functions to be called. Perhaps the problem is caused by something other than iterator categories after all.

in reply to:  1 comment:2 by Neil Groves, 8 years ago

Replying to anonymous:

Strangely, removing the line

auto c = vector<int>(b::begin(b), b::end(b));

results in the output "1, 1" instead of "0, 0", so it seems like merely chaining together adaptors causes the functions to be called. Perhaps the problem is caused by something other than iterator categories after all.

This is because range adaptors are applied lazily. Therefore the change in invocation counts is correct behaviour.

comment:3 by Neil Groves, 8 years ago

Status: newassigned

The reason you originally get 5,3 as a result is because the Filtered adaptor requires a ForwardPassRange since it needs to check adjacent elements.

http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/reference/adaptors/reference/filtered.html

Your code snippet is legal since it isn't a single-pass range as the input. Passing a genuine SinglePassRange to an adaptor requiring a ForwardRange will typically trigger a compile-time error with a Concept Assert. Having looked through the code I can see that I should add some more concept assert statements to ensure invalid code fails to compile.

comment:4 by Neil Groves, 8 years ago

Concept checking has been added to all of the Boost.Range adaptors. I have added 24 compilation failure unit tests to cover adaptors that require more than a SinglePassRange.

I'll watch the unit tests on develop for a few cycles and merge to master when the release cycle allows.

comment:5 by Neil Groves, 8 years ago

Milestone: To Be DeterminedBoost 1.57.0

in reply to:  3 comment:6 by anonymous, 8 years ago

Your code snippet is legal since it isn't a single-pass range as the input.

Isn't the input to filtered the output from transformed? The documentation for transformed says the range category is single-pass. Wouldn't that make my code snippet illegal?

comment:7 by Neil Groves, 8 years ago

Yes it does make it illegal. This is what I was thinking, but not what I wrote in my previous comment! I meant that the code snippet was illegal. This was why I was mentioning that I ought to make the error more obvious at compile-time with Concept Assertions.

I'm sorry I messed up my comment previously. I'll merge the change in when this is allowed by the Boost release cycle.

comment:8 by anonymous, 8 years ago

Milestone: Boost 1.57.0Boost 1.56.0

Release window for 1.56 has been extended so I can put this into 1.56.

comment:9 by Neil Groves, 8 years ago

Resolution: fixed
Status: assignedclosed

Merged to master and ready for release 1.56.

Note: See TracTickets for help on using tickets.