Perfect forwarding and std :: tuple (or another template class)

I have some difficulties with perfect shipment.

Here is my current level of understanding: Template + rvalue reference + std :: forward glue and special magic mode are activated when the rules for deducting templates do not have the same meaning as usual, but are created for perfect transfer. Example:

template <typename T> void outer(T&& t) { inner(std::forward<T>(t)); // perfect forwarding activated } 

But what happens if T is actually a template? For example, how can I improve the formatting of std :: tuple? If I use T && as an aboce, I lose all information about the type of objects contained in the tuple.
However, the following code may not work:

 template <typename... Args> void outer(std::tuple<Args...>&& t) { inner(std::forward<std::tuple<Args...>>(t)); use_args_types_for_something_else<Args...>(); // I need to have Args available } int main() { std::tuple<int, double, float> t(4, 5.0, 4.0f); outer(t); } 

The last gcc snapshot says:

 error: cannot bind 'std::tuple<int, double, float> lvalue to std::tuple<int, double, float>&& 

So, we are still in the general case without templates, where the lvalue cannot communicate with the rvalue reference. "Perfect forward mode" is not activated

So, I tried to hide and pass my tuple as a template template:

 template < typename... Args template <typename...> class T > void outer(T<Args...>&& t) { inner(std::forward<T<Args...>>(t)); use_args_type_for_something_else<Args...>(); } 

But I still get the same error.

+6
source share
1 answer

Perfect forwarding only works if the parameter type is the template type for the function, so the only way to achieve perfect forwarding is as in the first example:

 template <typename T> void outer(T&& t) { inner(std::forward<T>(t)); // perfect forwarding activated } 

The above works because it is a special case when T is output as SomeType& or SomeType&& .

This, however, does not mean that information about the type of tuple elements is lost forever. It is still available (although I don’t think you can type a package of templates). For example, you can still call use_args_types_for_something_else as follows:

 template <class T> struct call_uses_args; template <class ...Args> struct call_uses_args<std::tuple<Args...>> { void call() const { use_args_types_for_something_else<Args...>(); } }; template <typename TupleT> void outer(TupleT&& t) { inner(std::forward<TupleT>(t)); call_uses_args<typename std::remove_reference<TupleT>::type>().call(); } 

However, there can be no good general solution, but, I hope, such situations are rare. (For example, in this particular example, it might be easier to simply overload outer .)

+3
source

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


All Articles