I just wanted to listen to what I was facing with this very not-really-problem ("I think I need to decompose the rvalue links and keep the lvalue links intact") when implementing the effective version of Nick Athanasios folding Op<operation> . I had this mess:
template<class Pack, class Op> struct Foldable { mystery_trait_t<Pack> value; const Op& op; template<class RhsPack> auto operator*(const Foldable<RhsPack, Op>& rhs) const { return op(static_cast<std::decay_t<Pack>>( (op.f)(std::move(value), std::move(rhs.value)) )); } operator mystery_trait_t<Pack> () && { return std::move(value); } }; template<class Pack> auto NamedOperator::operator()(Pack&& value) const { return Foldable<Pack, NamedOperator>(std::forward<Pack>(value), *this); }
and (after some bewilderment, and then started asking the SO question and finding this existing question / answer and adding static_assert to my mystery_trait_t implementation, to make sure it was never called using the rvalue reference type!) it turned out that everything to me really needed was
template<class Pack, class Op> struct Foldable { Pack value; const Op& op; template<class RhsPack> auto operator*(const Foldable<RhsPack, Op>& rhs) const { return op( (op.f)(std::move(value), std::move(rhs.value)) ); } operator Pack () && { return std::move(value); } };
(see all my Wandbox code.)
This "answer" of mine does not introduce any new information, but I thought it would be useful to share, because it just shows that even if you think that you are deep in the metaprogramming of templates, and are sure that you need this behavior "conditional decay "... you really don't need it!
It may be a general rule that any_template<T&&> always a code smell. In the original Vittorio question, he did this twice, although both times he was hidden by decltype syntax
some_type_trait<decltype(xs)>...
source share