如何將輸入從輸入流直接插入到設定容器中?
這就是我需要的
while(n--)
{
cin>>s.emplace();
}
假設,我需要獲取 n 個輸入并將容器名稱設定為 's'
while(n--)
{
int x;
cin>>x;
s.emplace(x);
}
這作業正常,但我需要減少這一步。
uj5u.com熱心網友回復:
由于C 20可以使用std::ranges::copy,std::counted_iterator,std::istream_iterator,std::default_sentinel和std::inserter這樣做。在counted_iterator default_sentinel使它復制n從流元素。
例子:
#include <algorithm> // ranges::copy
#include <iostream>
#include <iterator> // counted_iterator, default_sentinel, istream_iterator, inserter
#include <set>
#include <sstream> // istringstream - only used for the example
int main() {
// just an example istream:
std::istringstream cin("1 1 2 2 3 3 4 4 5 5");
int n = 5;
std::set<int> s;
std::ranges::copy(
std::counted_iterator(std::istream_iterator<int>(cin), n),
std::default_sentinel,
std::inserter(s, s.end())
);
for(auto v : s) std::cout << v << ' ';
}
輸出將只包含 3 個元素,因為流中的前 5 個元素只有 3 個唯一元素:
1 2 3
在 C 20 之前,您可以copy_n以類似的方式使用:
std::copy_n(std::istream_iterator<int>(cin), n, std::inserter(s, s.begin()));
注意:如果n流中的元素實際上少于元素,則兩個版本都將具有未定義的行為。眾所周知,當涉及到準確地提供您想要的內容并且copy_n使錯誤檢查變得非常困難時,流是不可預測的。
為了安全起見,您可以使用以下方法創建一個counting_istream_iterator以從流中復制最多n元素std::copy:
std::copy(counting_istream_iterator<foo>(cin, n),
counting_istream_iterator<foo>{},
std::inserter(s, s.end()));
這樣的迭代器可以基于std::istream_iterator,看起來像這樣:
template<class T,
class CharT = char,
class Traits = std::char_traits<CharT>,
class Distance = std::ptrdiff_t>
struct counting_istream_iterator {
using difference_type = Distance;
using value_type = T;
using pointer = const T*;
using reference = const T&;
using iterator_category = std::input_iterator_tag;
using char_type = CharT;
using traits_type = Traits;
using istream_type = std::basic_istream<CharT, Traits>;
counting_istream_iterator() : // end iterator
isp(nullptr), count(0) {}
counting_istream_iterator(std::basic_istream<CharT, Traits>& is, size_t n) :
isp(&is), count(n 1)
{
*this; // read first value from stream
}
counting_istream_iterator(const counting_istream_iterator&) = default;
~counting_istream_iterator() = default;
reference operator*() const { return value; }
pointer operator->() const { return &value; }
counting_istream_iterator& operator () {
if(count > 1 && *isp >> value) --count;
else count = 0; // we read the number we should, or extraction failed
return *this;
}
counting_istream_iterator operator (int) {
counting_istream_iterator cpy(*this);
*this;
return cpy;
}
bool operator==(const counting_istream_iterator& rhs) const {
return count == rhs.count;
}
bool operator!=(const counting_istream_iterator& rhs) const {
return !(*this == rhs);
}
private:
std::basic_istream<CharT, Traits>* isp;
size_t count;
T value;
};
uj5u.com熱心網友回復:
您可以做的是創建您自己的可重用函式,該函式提供您想要的簡潔語法。你也可以把回圈放在那里。
這樣,您甚至可以進行正確的錯誤處理,同時保持主代碼的簡潔明了。
一個完全通用的可能如下所示:
#include <iostream>
#include <set>
#include <stdexcept>
template<typename ContainerT>
void populate(ContainerT& container, std::istream& stream, std::size_t n) {
using T = typename ContainerT::value_type;
while(n--) {
T tmp;
if(stream >> tmp) {
container.insert(container.end(), std::move(tmp));
}
else {
throw std::runtime_error("bad input");
}
}
}
int main() {
std::size_t n = 5;
std::set<int> s;
populate(s, std::cin, n);
}
你甚至可以變得更狂熱一點。例如,容器支持reserve()可以在開始填充容器之前呼叫它:
template<typename T>
concept HasReserve = requires(T x) {
{x.reserve(std::size_t{})};
};
// ...
ContainerT result;
if constexpr(HasReserve<ContainerT>) {
container.reserve(container.size() n);
}
//...
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/368075.html
