Remove rvalueness, keep links lvalue (is the standard type of attribute available?)

I am trying to write a function that returns a subset of a package of variational arguments in the form of std::tuple . A function should ideally not have excessive run-time costs (without extra copies), and it should allow users to access and modify lvalue links.

You must support value types, lvalue references, and const lvalue references. Temporaries ( rvalue links) must be "converted" to value types in order to avoid creating invalid links (temporary links).

An example of the desired results:

 int lr = 5; const int& clr = lr; auto t = make_subpack_tuple(lr, clr, 5); static_assert(is_same < decltype(t), std::tuple<int&, const int&, int> >{}, ""); // Ok, modifies lr: std::get<0>(t) = 10; // Compile-time error, intended: // std::get<1>(t) = 20; // Ok, 5 was moved into the tuple: std::get<2>(t) = 30; 

Incomplete implementation example:

 template<typename... Ts> auto make_subpack_tuple(Ts&&... xs) { return std::tuple < some_type_trait<decltype(xs)>... > ( std::forward<decltype(xs)>(xs)... ); } 

Am I trying to do what I'm trying to do?

Is there a standard attribute type that can be used instead of some_type_trait ? Or should I implement my own solution?

+5
source share
2 answers

The solution for you will be

 template<typename... Ts> auto make_subpack_tuple(Ts&&... xs) { return std::tuple<Ts...>(std::forward<Ts>(xs)...); } 

According to the rule for outputting template arguments , the Ts... parameter package will contain only cv-qualified types and lvalues. Information on this may be helpful.

+7
source

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)>... // should have been `Ts...` std::forward<decltype(xs)>(xs)... // could equally well be `std::forward<Ts>(xs)...` 
+1
source

Source: https://habr.com/ru/post/1234814/


All Articles