Allow iterator copy for lambda in transformed and filtered

Lambda has no default constructor nor a copy or move assignment.

range\test\adaptors.cpp is checking that produced ranges are copiable,
but it is not doing so the for lambda, or lambda like objects.

default_constructible_unary_fn uses an optional for default
construction.
I extended it to use its emplace facility to copy assign non copy
assignable types.
(see boost::optional 'Type Requierment':  'If T is not MoveAssignable,
it is still possible to reset the value of optional<T> using function
emplace():')
This commit is contained in:
Jean-Philippe DUFRAIGNE
2016-10-23 23:27:31 +01:00
parent e48b9c38e7
commit 1b4f8100ef
3 changed files with 101 additions and 10 deletions

View File

@ -32,6 +32,23 @@ public:
: m_impl(source)
{
}
default_constructible_unary_fn_wrapper(const default_constructible_unary_fn_wrapper& source)
: m_impl(source.m_impl)
{
}
default_constructible_unary_fn_wrapper& operator=(const default_constructible_unary_fn_wrapper& source)
{
if (source.m_impl)
{
// Lambda are not copy/move assignable.
m_impl.emplace(*source.m_impl);
}
else
{
m_impl.reset();
}
return *this;
}
template<typename Arg>
R operator()(const Arg& arg) const
{

View File

@ -51,6 +51,23 @@ namespace boost
bool operator()( IntegerT x ) const { return x % 2 != 0; }
};
struct lambda_init
{
};
struct lambda
{
lambda(const lambda_init& init) {}
lambda(const lambda& rhs) {}
template< class T1 >
bool operator()(T1) const { return false; }
private:
lambda() {}
lambda& operator=(const lambda& rhs) { return *this; }
};
template< class Container, class Pred >
void filtered_test_impl( Container& c, Pred pred )
{
@ -86,32 +103,53 @@ namespace boost
test_result2.end() );
}
template< class Rng >
void check_copy_assign(Rng r)
{
Rng r2 = r;
r2 = r;
}
template< class Container, class Pred >
void filtered_range_copy_assign(Container& c, Pred pred)
{
using namespace boost::adaptors;
check_copy_assign(c | filtered(pred));
check_copy_assign(adaptors::filter(c, pred));
}
template< class Container, class Pred, class PredInit >
void filtered_test_impl()
{
using namespace boost::assign;
Container c;
PredInit init;
Pred pred(init);
// test empty container
filtered_test_impl(c, Pred());
filtered_test_impl(c, pred);
// test one element
c += 1;
filtered_test_impl(c, Pred());
filtered_test_impl(c, pred);
// test many elements
c += 1,2,2,2,3,4,4,4,4,5,6,7,8,9,9;
filtered_test_impl(c, Pred());
filtered_test_impl(c, pred);
// test the range and iterator are copy assignable
filtered_range_copy_assign(c, pred);
}
template< class Container >
void filtered_test_all_predicates()
{
filtered_test_impl< Container, always_false_pred >();
filtered_test_impl< Container, always_true_pred >();
filtered_test_impl< Container, is_odd >();
filtered_test_impl< Container, is_even >();
filtered_test_impl< Container, always_false_pred, always_false_pred >();
filtered_test_impl< Container, always_true_pred, always_true_pred >();
filtered_test_impl< Container, is_odd, is_odd >();
filtered_test_impl< Container, is_even, is_even >();
filtered_test_impl< Container, lambda, lambda_init >();
}
void ticket_10988_single_pass()

View File

@ -38,6 +38,22 @@ namespace boost
int operator()(int x) const { return x / 2; }
};
struct lambda_init
{
};
struct lambda
{
lambda(const lambda_init& init) {}
lambda(const lambda& rhs) {}
int operator()(int x) const { return x + 1; }
private:
lambda() {}
lambda& operator=(const lambda& rhs) { return *this; }
};
template< class Container, class TransformFn >
void transformed_test_impl_core( Container& c, TransformFn fn )
{
@ -59,13 +75,29 @@ namespace boost
test_result2.begin(), test_result2.end() );
}
template< class Rng >
void check_copy_assign(Rng r)
{
Rng r2 = r;
r2 = r;
}
template< class Container, class TransformFn >
void transformed_range_copy_assign(Container& c, TransformFn fn)
{
using namespace boost::adaptors;
check_copy_assign(c | transformed(fn));
check_copy_assign(adaptors::transform(c, fn));
}
template< class Container, class TransformFn, class TransformFnInit >
void transformed_test_fn_impl()
{
using namespace boost::assign;
Container c;
TransformFn fn;
TransformFnInit init;
TransformFn fn( init );
// Test empty
transformed_test_impl_core(c, fn);
@ -77,13 +109,17 @@ namespace boost
// Test many elements
c += 1,1,1,2,2,2,2,2,3,4,5,6,7,8,9;
transformed_test_impl_core(c, fn);
// test the range and iterator are copy assignable
transformed_range_copy_assign(c, fn);
}
template< class Container >
void transformed_test_impl()
{
transformed_test_fn_impl< Container, double_x >();
transformed_test_fn_impl< Container, halve_x >();
transformed_test_fn_impl< Container, double_x, double_x >();
transformed_test_fn_impl< Container, halve_x, halve_x >();
transformed_test_fn_impl< Container, lambda, lambda_init >();
}
void transformed_test()