如何在 <T> 的容器上使用 std::sample 返回指针容器 <T*>?
Posted
技术标签:
【中文标题】如何在 <T> 的容器上使用 std::sample 返回指针容器 <T*>?【英文标题】:How can I return a container of pointers <T*> using std::sample on a container of <T>? 【发布时间】:2017-10-16 18:29:18 【问题描述】:我有一个 vector<T> input
,我想通过 STL C++17 (http://en.cppreference.com/w/cpp/algorithm/sample) 中的 std::sample
算法从中获取 n 个随机选择的元素。如果results
是vector<T>
类型,则代码可以正常工作。
代码示例 1(未返回指针)
auto getSamples(unsigned int noSamples, const vector<T> &input)
vector<T> results;
std::mt19937 twisterEngine;
std::sample(input.begin(), input.end(), std::back_inserter(results),
noSamples, twisterEngine);
return results;
但是,我不是在寻找存储在 input
中的元素的值/副本,而是希望获得指向 n 采样元素的指针。有什么技巧可以让我仅使用标准 c++ 代码(例如,不使用 boost 库等)获取 vector<T*> results
返回的指针吗?我需要如何调整以下代码才能完成?
代码示例 2(打算返回指针)
auto getSamples(unsigned int noSamples, const vector<T> &input)
vector<T*> results;
std::mt19937 twisterEngine;
std::sample(input.begin(), input.end(), std::back_inserter(results),
noSamples, twisterEngine);
return results;
【问题讨论】:
我会不返回指向样本的指针,因为input
是一个函数局部向量,所以你会传回一个悬空指针向量。唯一安全的情况是input
被const&
传递,并且您可以保证input
将在results
的生命周期内存在
调整了代码,使输入由 const& 传递。但是,我想在结果中返回指针。
我不认为sample
是正确的算法。我会用所有可用的指针填充一个向量,然后选择该向量随机排列的第一个 n
元素
...erm 或在包含所有指针的向量上使用sample
(您需要先填充它)。有点困惑,因为我第一次看到sample
【参考方案1】:
您只需要一个OutputIterator
。它实际上并没有必须 像迭代器一样发出一些东西。它可以只是……完全做其他事情。比如,调用一个函数。
#include <iterator>
template <class F>
struct function_output_iterator
F f;
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
function_output_iterator& operator++() return *this;
function_output_iterator& operator*() return *this;
function_output_iterator& operator++(int) return *this;
template <class U,
std::enable_if_t<!std::is_base_of<
function_output_iterator, std::decay_t<U>>, int> = 0>
void operator=(U&& u)
f(std::forward<U>(u));
;
template <class F>
function_output_iterator(F ) -> function_output_iterator<F>;
然后,你可以做任何你想做的任意操作:
auto getSamples(unsigned int noSamples, const vector<T> &input)
vector<T*> results;
results.reserve(noSamples);
std::mt19937 twisterEngine;
std::sample(input.begin(), input.end(),
function_output_iterator[&](T const& elem) results.push_back(&elem); , // <==
noSamples, twisterEngine);
return results;
【讨论】:
或者boost::make_function_output_iterator
如果你不想自己写(啊,我现在看到 OP 说没有 Boost,但仍然可能对没有此类限制的其他人有用)跨度>
@Praetorian 我注意到 Boost 的 operator*
返回一个已实现 operator=
的代理 - 你知道他们为什么这样做吗? (出于某种原因,我认为它比这更正确)
不知道,Google 搜索出现了 this proposal(来自 Boost 作者),上面写着 这个迭代器的动机是创建一个符合要求的输出迭代器并非易事,尤其是因为正确的实现通常需要一个代理对象。,但我想不出有什么不同的情况。还找到了this comment,所以你这个问题已经有一段时间了:)
@Praetorian HA!确实,也许我应该问一个适当的问题或其他什么。
@Barry:它更正确,因为它阻止你写 out_it = val
或 ****out_it = val
并且让它们意味着同样的事情。你真的应该做 boost 所做的事情,这使得只有 *out_it = val
合法以上是关于如何在 <T> 的容器上使用 std::sample 返回指针容器 <T*>?的主要内容,如果未能解决你的问题,请参考以下文章
c++11 用 std::swap vs operator=(T&&) 清除容器
如何使用 std::optional<T>::emplace 的第二个重载
std::vector<std::array<T, N>> 或 std::array<std::vector<T>,N> 类型的数组如何存储在内存中?