mirror of
https://github.com/boostorg/range.git
synced 2025-07-30 21:07:23 +02:00
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:
@ -32,6 +32,23 @@ public:
|
|||||||
: m_impl(source)
|
: 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>
|
template<typename Arg>
|
||||||
R operator()(const Arg& arg) const
|
R operator()(const Arg& arg) const
|
||||||
{
|
{
|
||||||
|
@ -51,6 +51,23 @@ namespace boost
|
|||||||
bool operator()( IntegerT x ) const { return x % 2 != 0; }
|
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 >
|
template< class Container, class Pred >
|
||||||
void filtered_test_impl( Container& c, Pred pred )
|
void filtered_test_impl( Container& c, Pred pred )
|
||||||
{
|
{
|
||||||
@ -86,32 +103,53 @@ namespace boost
|
|||||||
test_result2.end() );
|
test_result2.end() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template< class Rng >
|
||||||
|
void check_copy_assign(Rng r)
|
||||||
|
{
|
||||||
|
Rng r2 = r;
|
||||||
|
r2 = r;
|
||||||
|
}
|
||||||
|
|
||||||
template< class Container, class Pred >
|
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()
|
void filtered_test_impl()
|
||||||
{
|
{
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
|
|
||||||
Container c;
|
Container c;
|
||||||
|
PredInit init;
|
||||||
|
Pred pred(init);
|
||||||
|
|
||||||
// test empty container
|
// test empty container
|
||||||
filtered_test_impl(c, Pred());
|
filtered_test_impl(c, pred);
|
||||||
|
|
||||||
// test one element
|
// test one element
|
||||||
c += 1;
|
c += 1;
|
||||||
filtered_test_impl(c, Pred());
|
filtered_test_impl(c, pred);
|
||||||
|
|
||||||
// test many elements
|
// test many elements
|
||||||
c += 1,2,2,2,3,4,4,4,4,5,6,7,8,9,9;
|
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 >
|
template< class Container >
|
||||||
void filtered_test_all_predicates()
|
void filtered_test_all_predicates()
|
||||||
{
|
{
|
||||||
filtered_test_impl< Container, always_false_pred >();
|
filtered_test_impl< Container, always_false_pred, always_false_pred >();
|
||||||
filtered_test_impl< Container, always_true_pred >();
|
filtered_test_impl< Container, always_true_pred, always_true_pred >();
|
||||||
filtered_test_impl< Container, is_odd >();
|
filtered_test_impl< Container, is_odd, is_odd >();
|
||||||
filtered_test_impl< Container, is_even >();
|
filtered_test_impl< Container, is_even, is_even >();
|
||||||
|
filtered_test_impl< Container, lambda, lambda_init >();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ticket_10988_single_pass()
|
void ticket_10988_single_pass()
|
||||||
|
@ -38,6 +38,22 @@ namespace boost
|
|||||||
int operator()(int x) const { return x / 2; }
|
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 >
|
template< class Container, class TransformFn >
|
||||||
void transformed_test_impl_core( Container& c, TransformFn fn )
|
void transformed_test_impl_core( Container& c, TransformFn fn )
|
||||||
{
|
{
|
||||||
@ -59,13 +75,29 @@ namespace boost
|
|||||||
test_result2.begin(), test_result2.end() );
|
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 >
|
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()
|
void transformed_test_fn_impl()
|
||||||
{
|
{
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
|
|
||||||
Container c;
|
Container c;
|
||||||
TransformFn fn;
|
TransformFnInit init;
|
||||||
|
TransformFn fn( init );
|
||||||
|
|
||||||
// Test empty
|
// Test empty
|
||||||
transformed_test_impl_core(c, fn);
|
transformed_test_impl_core(c, fn);
|
||||||
@ -77,13 +109,17 @@ namespace boost
|
|||||||
// Test many elements
|
// Test many elements
|
||||||
c += 1,1,1,2,2,2,2,2,3,4,5,6,7,8,9;
|
c += 1,1,1,2,2,2,2,2,3,4,5,6,7,8,9;
|
||||||
transformed_test_impl_core(c, fn);
|
transformed_test_impl_core(c, fn);
|
||||||
|
|
||||||
|
// test the range and iterator are copy assignable
|
||||||
|
transformed_range_copy_assign(c, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class Container >
|
template< class Container >
|
||||||
void transformed_test_impl()
|
void transformed_test_impl()
|
||||||
{
|
{
|
||||||
transformed_test_fn_impl< Container, double_x >();
|
transformed_test_fn_impl< Container, double_x, double_x >();
|
||||||
transformed_test_fn_impl< Container, halve_x >();
|
transformed_test_fn_impl< Container, halve_x, halve_x >();
|
||||||
|
transformed_test_fn_impl< Container, lambda, lambda_init >();
|
||||||
}
|
}
|
||||||
|
|
||||||
void transformed_test()
|
void transformed_test()
|
||||||
|
Reference in New Issue
Block a user