Skip to content

Commit d45c47b

Browse files
author
Ryan Haining
committed
Updates FnPartials to move stored_arg when rvalue
Overloads `operator|` for rvalue and lvalue `Pipeable`s and downcasts accordingly. Adds rvalue-reference qualified overloads to FnPartial `operator|` that calls `std::move(stored_arg)` when creating the actual iterable object. This allows a move-only callable to get passed by value, but only moves, all the way into the itertool. ``` // both should work iter::some_itertool(sequence, MoveOnlyCallable{}); sequence | iter::some_itertool(MoveOnlyCallable{}); ``` I did attempt passing a `std::reference_wrapper` from the `FnPartial` but the iteration happens after the `FnPartial` is destroyed, So the following is unsafe: ``` // unsafe, wrong template <typename Container> auto operator()(Container&& container) const { if constexpr (std::is_copy_constructible_v<T>) { return F{}(stored_arg, std::forward<Container>(container)); } else { return F{}(std::ref(stored_arg), std::forward<Container>(container)); } } ``` Setting the stage to fix #89
1 parent 1c828d0 commit d45c47b

File tree

1 file changed

+30
-8
lines changed

1 file changed

+30
-8
lines changed

cppitertools/internal/iterbase.hpp

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,14 @@ namespace iter {
353353
template <typename ItTool>
354354
struct Pipeable {
355355
template <typename T>
356-
#if defined(__GNUC__) && !defined(__clang__)
357-
[[gnu::no_dangling]]
356+
#if defined(__GNUC__) && !defined(__clang__)
357+
[[gnu::no_dangling]]
358358
#endif
359+
friend decltype(auto) operator|(T&& x, Pipeable&& p) {
360+
return static_cast<ItTool&&>(p)(std::forward<T>(x));
361+
}
362+
363+
template <typename T>
359364
friend decltype(auto) operator|(T&& x, const Pipeable& p) {
360365
return static_cast<const ItTool&>(p)(std::forward<T>(x));
361366
}
@@ -378,11 +383,17 @@ namespace iter {
378383
protected:
379384
template <typename T>
380385
struct FnPartial : Pipeable<FnPartial<T>> {
386+
static_assert(!std::is_reference_v<T>);
381387
mutable T stored_arg;
382-
constexpr FnPartial(T in_t) : stored_arg(in_t) {}
388+
constexpr FnPartial(T in_t) : stored_arg(std::move(in_t)) {}
383389

384390
template <typename Container>
385-
auto operator()(Container&& container) const {
391+
auto operator()(Container&& container) && {
392+
return F{}(std::move(stored_arg), std::forward<Container>(container));
393+
}
394+
395+
template <typename Container>
396+
auto operator()(Container&& container) const& {
386397
return F{}(stored_arg, std::forward<Container>(container));
387398
}
388399
};
@@ -403,10 +414,15 @@ namespace iter {
403414
template <typename T>
404415
struct FnPartial : Pipeable<FnPartial<T>> {
405416
mutable T stored_arg;
406-
constexpr FnPartial(T in_t) : stored_arg(in_t) {}
417+
constexpr FnPartial(T in_t) : stored_arg(std::move(in_t)) {}
407418

408419
template <typename Container>
409-
auto operator()(Container&& container) const {
420+
auto operator()(Container&& container) && {
421+
return F{}(std::forward<Container>(container), std::move(stored_arg));
422+
}
423+
424+
template <typename Container>
425+
auto operator()(Container&& container) const& {
410426
return F{}(std::forward<Container>(container), stored_arg);
411427
}
412428
};
@@ -469,10 +485,16 @@ namespace iter {
469485
template <typename T>
470486
struct FnPartial : Pipeable<FnPartial<T>> {
471487
mutable T stored_arg;
472-
constexpr FnPartial(T in_t) : stored_arg(in_t) {}
488+
constexpr FnPartial(T in_t) : stored_arg(std::move(in_t)) {}
473489

474490
template <typename Container>
475-
auto operator()(Container&& container) const {
491+
auto operator()(Container&& container) && {
492+
return IterToolFnOptionalBindSecond{}(
493+
std::forward<Container>(container), std::move(stored_arg));
494+
}
495+
496+
template <typename Container>
497+
auto operator()(Container&& container) const& {
476498
return IterToolFnOptionalBindSecond{}(
477499
std::forward<Container>(container), stored_arg);
478500
}

0 commit comments

Comments
 (0)