c++ templates c++11 typetraits

c++ - Escriba rasgo para verificar que todos los tipos en un paquete de parámetros sean copiables



templates c++11 (4)

Necesito un rasgo de tipo para verificar si todos los tipos en un paquete de parámetros son copiables. Esto es lo que hice hasta ahora. La función principal contiene algunos casos de prueba para verificar la funcionalidad.

#include <type_traits> #include <string> #include <memory> template <class... Args0toN> struct areCopyConstructible; template<> struct areCopyConstructible<> : std::true_type {}; template <class Arg0, class... Args1toN, class std::enable_if< !std::is_copy_constructible<Arg0>::value>::type* = nullptr > struct areCopyConstructible : std::false_type {}; template <class Arg0, class... Args1toN, class std::enable_if< std::is_copy_constructible<Arg0>::value>::type* = nullptr > struct areCopyConstructible : areCopyConstructible<Args1toN...> {}; int main() { static_assert(areCopyConstructible<>::value, "failed"); static_assert(areCopyConstructible<int>::value, "failed"); static_assert(areCopyConstructible<int, std::string>::value, "failed"); static_assert(!areCopyConstructible<std::unique_ptr<int> >::value, "failed"); static_assert(!areCopyConstructible<int, std::unique_ptr<int> >::value, "failed"); static_assert(!areCopyConstructible<std::unique_ptr<int>, int >::value, "failed"); }

Enlace al ejemplo en vivo

Mi idea era verificar recursivamente, si el elemento principal del paquete es copiable o no y seguir adelante, con la cola. Desafortunadamente, no entiendo esta idea para compilar. Mi conocimiento sobre plantillas variadic no es muy avanzado. Supongo que ese enable-if after parameter pack en la lista de plantillas no funciona. No tengo idea. ¿Alguien tiene un buen consejo, cómo resolver el problema?


Prefiero el truco bool_pack @ Columbo. Primero una plantilla para probar que todo en un paquete de parámetros bool es true :

template<bool...> struct bool_pack; template<bool... bs> using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;

Entonces

template<class... Ts> using areCopyConstructible = all_true<std::is_copy_constructible<Ts>::value...>;


Primero defina una utilidad reutilizable para probar si cada predicado en un paquete es verdadero:

template<typename... Conds> struct and_ : std::true_type { }; template<typename Cond, typename... Conds> struct and_<Cond, Conds...> : std::conditional<Cond::value, and_<Conds...>, std::false_type>::type { };

Entonces es trivial usar eso con is_copy_constructible (o cualquier otro rasgo de tipo unario):

template<typename... T> using areCopyConstructible = and_<std::is_copy_constructible<T>...>;

Una ventaja de definir and_ like this es que cortocircuita, es decir, deja de instanciar is_copy_constructible para el resto del paquete después del primer resultado falso.


Sé que es una vieja pregunta, pero como pronto tendremos C ++ 17, recomiendo echar un vistazo a std::conjunction . Con eso podrías escribir algo como esto

template <typename ...Args> using areCopyConstructible = typename std::conjunction<std::is_copy_constructible<Args>...>::type;


Si la herencia de std::true_type o std::false_type no es importante, esto se puede hacer de manera directa sin SFINAE:

template <class... Args0toN> struct areCopyConstructible; template<> struct areCopyConstructible<> : std::true_type {}; template <class Arg0, class... Args1toN> struct areCopyConstructible<Arg0, Args1toN...> { static constexpr bool value = std::is_copy_constructible<Arg0>::value && areCopyConstructible<Args1toN...>::value; };

Si desea heredar de std::true_type o std::false_type , puede usar std::conditional :

template <class... Args0toN> struct areCopyConstructible; template<> struct areCopyConstructible<> : std::true_type {}; template <class Arg0, class... Args1toN> struct areCopyConstructible<Arg0, Args1toN...> : std::conditional<std::is_copy_constructible<Arg0>::value, areCopyConstructible<Args1toN...>, std::false_type >::type {};