如何创建一个将一个集合的内容添加到另一个集合的功能,如果可能,可以使用std::back_inserter()
来提高效率?我没有看到push_back()
的明显特征,而且我不是std::enable_if
的专家,但是我希望通过某种组合可以达到以下效果:
// 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()));
}
答案 0 :(得分:3)
如何创建一个将一个集合的内容添加到另一个集合的函数,如果可能的话,使用back_inserter来提高效率?
我想您可以声明一个模板函数,当有std::true_type
时返回push_back()
template <typename T>
constexpr auto hasPushBack (int)
-> decltype( std::declval<T>().push_back(*(std::declval<T>().begin())),
std::true_type() );
和返回std::false_type
template <typename>
constexpr std::false_type hasPushBack (long);
因此您可以按以下方式修改功能
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())); }
如果您可以使用C ++ 14或更高版本,则还可以使用值定义模板变量
template <typename T>
constexpr bool hasPushBack_v = decltype(hasPushBack<T>(0))::value;
您可以简化以下功能
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())); }
答案 1 :(得分:2)
只是为了好玩,从C ++ 14开始,您还可以使用变量模板
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()));
}
答案 2 :(得分:1)
您可以在SFINAE和std::enable_if
的帮助下申请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()));
}