Escriba trait para comprobar que todos los tipos de un paquete de parámetros son construibles mediante copia


Necesito un rasgo de tipo para comprobar si todos los tipos de un paquete de parámetros son construibles por copia. Esto es lo que he hecho hasta ahora. La función principal contiene algunos casos de prueba, para comprobar 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 comprobar recursivamente, si el elemento head del pack es copy-constructible o no y seguir adelante, con la cola. Desafortunadamente, no entiendo esta idea para compilar. Mi conocimiento sobre plantillas variádicas no es muy avanzado. Supongo, que habilitar - si después de paquete de parámetros en la lista de plantillas no funciona. No tengo idea. ¿Alguien tiene un buen consejo, ¿cómo resolver el problema?

Author: meddle0106, 2015-04-13

4 answers

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_ así es que cortocircuita, es decir, deja de instanciar is_copy_constructible para el resto del paquete después del primer resultado falso.

 29
Author: Jonathan Wakely,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-13 11:15:46

Prefiero el truco de @Columbo bool_pack. 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...>;
 9
Author: T.C.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-13 11:10:46

Si la herencia de std::true_type o std::false_type no es importante, entonces 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 utilizar 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
{};
 8
Author: Anton Savin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-13 11:56:23

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

template <typename ...Args>
using areCopyConstructible = typename std::conjunction<std::is_copy_constructible<Args>...>::type;
 3
Author: stryku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-26 11:37:11