valores retornan que procedimientos parametros lenguaje funciones funcion ejemplos con c++ c++11 tuples std-pair minmax

procedimientos - funciones que retornan valores en c++



¿Hay alguna manera de manejar fácilmente las funciones que devuelven std:: pairs? (6)

Con la vinculación estructurada de C ++ 1z, puede hacer directamente

auto [lhsMinIt, lhsMaxIt] = std::minmax_element(lhs.begin(), lhs.end());

C ++ 11 tiene la función std::minmax_element que devuelve un par de valores. Esto, sin embargo, es bastante confuso de manejar y leer, y produce una variable adicional inútil para contaminar el alcance.

auto lhsMinmax = std::minmax_element(lhs.begin(), lhs.end()); int &lhsMin = *(lhsMinMax.first); int &lhsMax = *(lhsMinmax.second);

¿Hay una mejor manera de hacer esto? Algo como:

int lhsMin; int lhsMax; std::make_pair<int&, int&>(lhsMin, lhsMax).swap( std::minmax_element(lhs.begin(), lhs.end()));


En C ++ 14 o mayor

template<class=void, std::size_t...Is> auto indexer( std::index_sequence<Is...> ) { return [](auto&&f){ return f( std::integral_constant<std::size_t, Is>{}... ); }; } template<std::size_t N> auto indexer() { return indexer( std::make_index_sequence<N>{} ); } template<class F> auto fmap_over_tuple( F&& f ) { return [f=std::forward<F>(f)](auto&& tuple) { using Tuple = decltype(tuple); using Tuple_d = std::decay_t<Tuple>; auto index = indexer< std::tuple_size< Tuple_d >::value >(); return index( [&f, &tuple](auto&&...Is) { using std::get; return std::make_tuple( f( get<Is>( std::forward<Tuple>(tuple) ) )... ); } ); }; }

entonces fmap_over_tuple toma un objeto de función. Devuelve un objeto de función que, cuando pasa una tupla, procede a llamar al objeto de función en cada elemento de la tupla y genera una tupla a partir de él.

Luego escribimos tupla de desreferencia:

auto dereference_tuple = fmap_over_tuple( [](auto&& e) { return *e; } );

Ahora en C ++ 17 lo hacemos:

auto[Min, Max] = dereference_tuple( std::minmax_element(lhs.begin(), lhs.end() );

y Bob es tu tío.

En C ++ 11, solo haz lo que hiciste. Lo suficientemente limpio

C ++ 14 ejemplo en vivo .


Esto parece suficiente de un caso común para solicitar una función auxiliar:

template <class T, std::size_t...Idx> auto deref_impl(T &&tuple, std::index_sequence<Idx...>) { return std::tuple<decltype(*std::get<Idx>(std::forward<T>(tuple)))...>(*std::get<Idx>(std::forward<T>(tuple))...); } template <class T> auto deref(T &&tuple) -> decltype(deref_impl(std::forward<T>(tuple), std::make_index_sequence<std::tuple_size<std::remove_reference_t<T>>::value>{})) { return deref_impl(std::forward<T>(tuple), std::make_index_sequence<std::tuple_size<std::remove_reference_t<T>>::value>{}); } // ... int lhsMin; int lhsMax; std::tie(lhsMin,lhsMax) = deref(std::minmax_element(lhs.begin(), lhs.end()));

index_sequence es C ++ 14, pero se puede realizar una implementación completa en C ++ 11 .

Nota: Mantendré el decltype repetido en el tipo de devolución de deref incluso en C ++ 14, para que SFINAE pueda aplicar.

Véalo en vivo en Coliru


No hay forma de asignar dos referencias a la vez en la revisión actual del estándar, si eso es lo que está buscando. Tenga en cuenta que ninguna de las otras respuestas lo hace, excepto Barry''s que requiere C ++ 17 y una plantilla auxiliar.

Sin embargo, si desea un acceso de lectura y escritura a sus elementos mínimos y máximos, ¿por qué no simplemente ir con los iteradores que minmax_element proporciona minmax_element directamente? Es probable que genere códigos de máquina idénticos como el uso de referencias de todos modos, al menos si su lhs es ContiguousContainer pero quizás también en otros casos.

Necesitará confiar un poco menos en la deducción de tipo automático, por ejemplo,

decltype(lhs.begin()) lhsMinIt, lhsMaxIt; std::tie(lhsMinIt, lhsMaxIt) = std::minmax_element(lhs.begin(), lhs.end()); /* now access your minimum and maximum as *lhsMinIt and *lhsMaxIt */

Si sabe que el tipo de lhs será uno de los contenedores estándar, puede usar una designación de tipo bit cleaner decltype(lhs)::iterator .


Para evitar contaminar su alcance, puede adjuntar la tarea en un ámbito más pequeño:

int lhsMin, lhsMax; { auto it = std::minmax_element(lhs.begin(), lhs.end()); lhsMin = *it.first; lhsMax = *it.second; }

alternativamente, puedes usar un lambda

int lhsMin, lhsMax; std::tie(lhsMin, lhsMax) = [&]{ auto it = std::minmax_element(lhs.begin(), lhs.end()); return std::make_tuple(*it.first, *it.second); }();


Simplemente sería más directo y escribiría mi propia versión de minmax_element :

template <class Iter, class R = typename iterator_traits<Iter>::reference> std::pair<R,R> deref_minmax(Iter first, Iter last) { auto iters = std::minmax_element(first, last); return std::pair<R,R>{*iters.first, *iters.second}; }

Que es entonces solo:

int lo, hi; std::tie(lo, hi) = deref_minmax(lhs.begin(), lhs.end());

Esto limitaría a una sola copia de los elementos (que no es gran cosa con int ), también le permitirá mantener el acceso a las referencias en el contenedor real.

En C ++ 17, por diversión, podríamos escribir un dereferencer generalizado:

template <class Tuple> auto deref(Tuple&& tup) { return std::apply([](auto... args) { return std::tuple <decltype(*args)...>(*args...); }, tup); } auto& [lo, hi] = deref(std::minmax_element(lhs.begin(), lhs.end()));

Aquí lo y hi son referencias en el contenedor en sí.