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");
}
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
{};