tipo retorno que procedimientos parametros parametro lenguaje funciones ejemplos ejemplo con c++ c++11 argument-dependent-lookup noexcept

c++ - que - ¿Cómo escribo un tipo de retorno final habilitado para ADL, o especificación noexcept?



funciones y procedimientos en python (4)

Imagina que estoy escribiendo una plantilla de contenedor o algo así. Y llega el momento de especializar std::swap for it. Como buen ciudadano, habilitaré ADL haciendo algo como esto:

template <typename T> void swap(my_template<T>& x, my_template<T>& y) { using std::swap; swap(x.something_that_is_a_T, y.something_that_is_a_T); }

Esto es muy limpio y todo. Hasta que yo quiera agregar una especificación de excepción. Mi swap es noexcept mientras que el swap para T sea noexcept . Entonces, estaría escribiendo algo como:

template <typename T> void swap(my_template<T>& x, my_template<T>& y) noexcept(noexcept(swap(std::declval<T>(), std::declval<T>())))

El problema es que el swap en el que se necesita ser el swap descubierto por ADL o std::swap . ¿Cómo manejo esto?



Creo que lo movería a un espacio de nombres separado

namespace tricks { using std::swap; template <typename T, typename U> void swap(T &t, U &u) noexcept(noexcept(swap(t, u))); } template <typename T> void swap(my_template<T>& x, my_template<T>& y) noexcept(noexcept(tricks::swap(std::declval<T>(), std::declval<T>()))) { using std::swap; swap(x.something_that_is_a_T, y.something_that_is_a_T); }

Alternativamente, puede mover todo el código hacia arriba en tricks y delegar allí.


En lugar de declarar pero no definir una plantilla de función, que probablemente cause confusión, escribiría mi propio rasgo de tipo (que es lo que probablemente debería estar en la biblioteca estándar). Siguiendo el ejemplo de la biblioteca estándar, definiría algo como lo siguiente:

#include <type_traits> #include <utility> namespace adl { using std::swap; template<typename T, typename U> struct is_nothrow_swappable : std::integral_constant< bool, noexcept(swap(std::declval<T &>(), std::declval<U &>())) > { }; } // namespace adl

Tenemos que definir nuestro propio espacio de nombres para importar std :: swap (para evitar que se lo entreguen a todos), pero, por supuesto, si fuera en la biblioteca estándar no sería necesario porque ya pueden hacer llamadas de intercambio no calificadas.


Hay un problema similar para los tipos de devolución:

// Want to be compatible with both boost::tuple and std::tuple template<typename Tuple> auto first(Tuple&& tuple) -> /* ??? */ { // Introduce name into scope using std::get; // but ADL can still pick boost::get for boost::tuple return get<0>(std::forward<Tuple>(tuple)); }

El uso de decltype( get<0>(std::forward<Tuple>(tuple)) ) no es correcto ya que get no está dentro del alcance.

Las soluciones posibles son:

  • Presentando una plantilla ficticia ( get en mi ejemplo, swap en su caso) en el ámbito de aplicación adjunto; esto incluye colocar la declaración using std::swap en el espacio de nombres adjunto, con el inconveniente de contaminar el espacio de nombres.

  • Uso de un rasgo de tipo: typename std::tuple_element<0, typename std::remove_reference<Tuple>::type>::type (en realidad este es problemático pero por razones que no pertenecen aquí) en mi ejemplo, y un valor potencial is_nothrow_swappable<T>::value en su caso. Las especializaciones luego permiten que la plantilla se extienda a otros tipos si es necesario.