Comment créer une fonction qui ajoute le contenu d'une collection à une autre, en utilisant std :: back_inserter ()
si possible pour plus d'efficacité? Je ne vois pas de trait évident pour push_back ()
et je ne suis pas un expert avec std :: enable_if
, mais j'espère qu'une combinaison produira l'effet des éléments suivants:
// IF HAS_PUSH_BACK: template<typename CIn, typename COut> void addAll(CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::back_inserter(to)); } // IF ! HAS_PUSH_BACK: template<typename CIn, typename COut> void addAll(CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::inserter(to, to.begin())); }
3 Réponses :
Comment créer une fonction qui ajoute le contenu d'une collection à une autre, en utilisant back_inserter si possible pour plus d'efficacité?
Je suppose que vous pouvez déclarer une fonction de modèle qui renvoie
std :: true_type
quand il y apush_back()
template<typename CIn, typename COut> std::enable_if_t<true == hasPushBack_v<COut>> addAll (CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::back_inserter(to)); } template<typename CIn, typename COut> std::enable_if_t<false == hasPushBack_v<COut>> addAll(CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::inserter(to, to.begin())); }et la fonction de restauration qui renvoiestd::false_type
template <typename T> constexpr bool hasPushBack_v = decltype(hasPushBack<T>(0))::value;afin que vous puissiez modifier vos fonctions comme suit
template<typename CIn, typename COut> typename std::enable_if<true == decltype(hasPushBack<COut>(0))::value>::type addAll (CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::back_inserter(to)); } template<typename CIn, typename COut> typename std::enable_if<false == decltype(hasPushBack<COut>(0))::value>::type addAll(CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::inserter(to, to.begin())); }Si vous pouvez utiliser C ++ 14 ou plus récent, vous pouvez également définir une variable de modèle avec la valeur
template <typename> constexpr std::false_type hasPushBack (long);et vous pouvez simplifier le fonctionne comme suit
template <typename T> constexpr auto hasPushBack (int) -> decltype( std::declval<T>().push_back(*(std::declval<T>().begin())), std::true_type() );
Vous pouvez appliquer SFINAE à l'aide de std :: enable_if
et std :: void_t
.
template <typename T, typename = void> struct has_push_back : std::false_type {}; template <typename T> struct has_push_back<T, std::void_t<decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))>> : std::true_type {}; // IF HAS_PUSH_BACK: template<typename CIn, typename COut> std::enable_if_t<has_push_back<std::remove_reference_t<COut>>::value> addAll(CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::back_inserter(to)); } // IF ! HAS_PUSH_BACK: template<typename CIn, typename COut> std::enable_if_t<!has_push_back<std::remove_reference_t<COut>>::value> addAll(CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::inserter(to, to.begin())); }
Juste pour le plaisir, à partir de C ++ 14, vous pouvez également utiliser le modèle de variable
template <class...> using void_t = void; // (compensate C++14 lack) template <class T, class = void> constexpr bool HasPushBack{false}; template <class T> constexpr bool HasPushBack<T, void_t< decltype(std::declval<T>().push_back(std::declval<typename std::decay_t<T>::value_type>()))> >{true}; template<typename CIn, typename COut, std::enable_if_t< HasPushBack<COut>,bool> = true> void addAll(CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::back_inserter(to)); } template<typename CIn, typename COut, std::enable_if_t<!HasPushBack<COut>,bool> = true> void addAll(CIn && from, COut && to) { std::copy(std::begin(from), std::end(from), std::inserter(to, to.begin())); }
Gentil et drôle. Malheureusement, std :: void_t
est C ++ 17 (mais il est facile de le remplacer dans C ++ 14)
@ max66 - vous avez raison. Je l'ai ajouté par souci d'exhaustivité.