C++ 如何获得向量中满足谓词的唯一PTR的子集?

C++ 如何获得向量中满足谓词的唯一PTR的子集?,c++,c++11,iteration,unique-ptr,predicate,C++,C++11,Iteration,Unique Ptr,Predicate,我有一个std::unique_ptr对象的向量。我想得到一个符合某些条件的所有向量项的集合。 我看到了std函数,但它们似乎都是测试谓词(并返回bool)或返回单个元素 是否有一种内置的机制来获取作为向量子集的集合?如果没有,是否有一种方法可以构造一个迭代器,根据任意谓词测试项目(以识别满足我的条件的项目)和一种机制来返回所有满足该谓词的项目?请注意,因为您有一个唯一的ptr向量,这些元素只能移动,即一旦您得到子集,原始向量将不再相同 最小破坏性方法是将向量分成两组,同时将所有内容保持在同一

我有一个
std::unique_ptr
对象的向量。我想得到一个符合某些条件的所有向量项的集合。 我看到了std函数,但它们似乎都是测试谓词(并返回bool)或返回单个元素


是否有一种内置的机制来获取作为向量子集的集合?如果没有,是否有一种方法可以构造一个迭代器,根据任意谓词测试项目(以识别满足我的条件的项目)和一种机制来返回所有满足该谓词的项目?

请注意,因为您有一个唯一的ptr向量,这些元素只能移动,即一旦您得到子集,原始向量将不再相同


最小破坏性方法是将向量分成两组,同时将所有内容保持在同一个向量中:

auto sep = std::stable_partition(vec.begin(), vec.end(), [](const auto& foo) {
    return foo->is_good();
});
// the part `vec.begin() .. sep` contains all "good" foos.
// the part `sep .. vec.end()` contains all "bad" foos.
如果顺序不重要。用法是一样的

如果要将坏的foos拆分为另一个向量,可以使用+将对象移出。请注意,这会在任何地方留下洞。使用
std::remove
清理它们

decltype(vec) bad_vec;
std::copy_if(std::make_move_iterator(vec.begin()),
             std::make_move_iterator(vec.end()),
             std::back_inserter(bad_vec),
             [](const auto& p) { return !p->is_good(); });
auto new_end = std::remove(vec.begin(), vec.end(), nullptr);
vec.erase(new_end, vec.end());
如果您不再关心“坏”对象,请使用:


如果您只想获取原始指针,而不是唯一的ptr本身,您可以使用
std::transform
填充
向量,然后
删除\u If
对其进行过滤。。。但在这一点上,编写for循环可能更容易

std::vector<int*> good_vec;
for (const auto& foo : vec) {
    if (foo->is_good()) {
        good_vec.push_back(foo.get());
    }
}
std::vector good\u vec;
用于(const auto&foo:vec){
如果(foo->is_good()){
好的。推回(foo.get());
}
}

因为你的向量拥有
唯一的\u ptr
(我们不复制)-我推荐你询问的第二个选项:一个迭代器,它只迭代那些与你的谓词匹配的元素。这正是

例如:

bool points_to_positive(int* ptr) { 
    return ptr != nullptr and *ptr > 0; 
}

// ...

std::vector<std::unique_ptr<int>> vec;

// ...

auto iterator = boost::make_filter_iterator(
    &points_to_positive, std::begin(vec), std::end(vec)
);
bool指向正(int*ptr){
返回ptr!=nullptr和*ptr>0;
}
// ...
std::vec;
// ...
自动迭代器=boost::生成过滤器迭代器(
&点到正,标准::开始(vec),标准::结束(vec)
);

但是,如果您计划多次进行该迭代,并且不想以时间换取空间,那么最好只复制@kennytm最后建议的选项中的实际指针。

您要求的是
std::copy_if
from
。对于无法复制的
唯一\u ptr
元素,这不是您想要的。示例代码:

#include <algorithm>
#include <array>
#include <cstdlib>
#include <experimental/array>
#include <iostream>
#include <type_traits>
#include <vector>

using std::cout;
using std::endl;
using std::size_t;

bool is_even( const int n )
{
  // True iff n is even.
  return n % 2 == 0;
}

std::ostream& operator<< ( std::ostream& os, const std::vector<int>& container )
{
  // Boilerplate instrumentation.
  for ( const int& x : container )
    os << x << ' ';

  return os;
}

int main(void)
{
  // Our input array, raw:
  constexpr int digits[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  // The number of input elements:
  constexpr size_t ndigits = std::extent<decltype(digits)>();
  // Container wrapping our input array:
  constexpr std::array<int, ndigits > numbers =
    std::experimental::to_array(digits);
  std::vector<int> even_numbers;

  even_numbers.reserve(ndigits); // Upper bound on output size.
  std::copy_if( numbers.cbegin(),
                numbers.cend(),
                std::back_inserter(even_numbers),
                is_even );
  even_numbers.shrink_to_fit();

  // Correct output is "2 4 6 8 "
  cout << even_numbers << endl;

  return EXIT_SUCCESS;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用std::cout;
使用std::endl;
使用std::size\u t;
布尔是偶数(常数整数n)
{
//如果n是偶数,则为真。
返回n%2==0;
}

std::ostream&Operator如果符合您的要求,是否复制?您希望返回的子集的类型是什么?原始向量是否需要改变?你真的需要更精确地指定你的问题。我希望子集也是Foo指针的向量。我不希望原始向量受到影响。我确实希望编辑子集向量中的项,并使这些编辑反映在原始向量中。我假设使用指针应该可以确保这一点。Richard-我想如果我删除了唯一的\u ptr要求,我会删除唯一的\u ptr要求并使用copy\u。如果我删除了唯一的\u ptr要求,是否有STL版本的filter\u iterator?@Craig:如果我的内存没有问题,标准库就缺少与迭代器相关的功能。。。但是你自己做并不难。它是一个相当大的锅炉板,但除此之外-与通常的迭代器相同,除了您的
操作符+++
操作符+
等。在计算满足谓词的元素时,实现会前进。您确定要建议OP复制
唯一的\u ptr
s吗?在底部添加了一行。其他几个答案给出了很好的选择!这些答案很好,我认为没有必要重复。我刚才为OP提出的问题提供了一些演示代码。不过,看看
unique\u ptr
s是如何无法复制的,你的建议行得通吗?(我试图在这里拯救你的选票…)我在底部添加了一个更强烈的警告,这是OP要求的,而不是他或她想要的。也就是说,将
unique_ptr
更改为
shared_ptr
或其他可复制类型与使用其他不复制的算法一样有效。一个
std::reference_wrapper
的向量或原始向量的索引是其他非破坏性选项。
#include <algorithm>
#include <array>
#include <cstdlib>
#include <experimental/array>
#include <iostream>
#include <type_traits>
#include <vector>

using std::cout;
using std::endl;
using std::size_t;

bool is_even( const int n )
{
  // True iff n is even.
  return n % 2 == 0;
}

std::ostream& operator<< ( std::ostream& os, const std::vector<int>& container )
{
  // Boilerplate instrumentation.
  for ( const int& x : container )
    os << x << ' ';

  return os;
}

int main(void)
{
  // Our input array, raw:
  constexpr int digits[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  // The number of input elements:
  constexpr size_t ndigits = std::extent<decltype(digits)>();
  // Container wrapping our input array:
  constexpr std::array<int, ndigits > numbers =
    std::experimental::to_array(digits);
  std::vector<int> even_numbers;

  even_numbers.reserve(ndigits); // Upper bound on output size.
  std::copy_if( numbers.cbegin(),
                numbers.cend(),
                std::back_inserter(even_numbers),
                is_even );
  even_numbers.shrink_to_fit();

  // Correct output is "2 4 6 8 "
  cout << even_numbers << endl;

  return EXIT_SUCCESS;
}