Is it possible to implement a C++ function which gives a string representation of every std::vector<T>, as long as the element of type T can be appended to an output stream like
T x;
...
std::cout << x << std::endl;
The string representation should look like
[x, y, z]
I've attempted the following, but what should ? be?
template <typename T> std::string vectorToString(std::vector<T>& vec) {
std::string s;
for (T element : vec) {
?
}
return s;
}
You'll want a stringstream to do the formatting:
std::ostringstream ss;
ss << '['
bool first = true;
for (T const & element : vec) {
if (!first) {
ss << ", ";
}
ss << element;
first = false;
}
ss << ']';
return ss.str();
Use a std::ostringstream instance for ? and return std::ostringstream::str():
std::ostringstream s;
s << "[";
for (auto i(vec.begin()); i != vec.end(); i++)
{
if (vec.begin() != i) s << ", ";
s << *i;
}
s << "]";
return s.str();
If you are working on C++11, you can use this simple version:
#include <sstream>
#include <algorithm>
using namespace std;
template<typename T>
string format(vector<T> const& v)
{
if (v.empty()) return "[]";
ostringstream ss;
ss << "[" << v[0];
for_each(begin(v) + 1, end(v), [&ss] (T const& s) { ss << ", " << s; });
ss << "]";
return ss.str();
}
If you want to make it generic for other types of collections (not just vector) or even for sub-ranges of a collection, you can generalize it this way:
#include <sstream>
#include <algorithm>
using namespace std;
template<typename It>
string format(It b, It e)
{
if (b == e) return "[]";
ostringstream ss;
ss << "[" << *b;
for_each(++b, e, [&ss] (decltype(*b)& s) { ss << ", " << s; });
ss << "]";
return ss.str();
}
template<typename C>
string format(C const& c)
{
return format(begin(c), end(c));
}
int main()
{
vector<int> v = { 4, 5, 5, 8 };
cout << format(v) << endl;
return 0;
}
Using algorithms, which usually simplify code (not sure if in this case, but added for the sake of completion):
template <typename T>
std::string toString( std::vector<T> const & v ) {
if (v.empty())
return "[]";
typename std::vector<T>::const_iterator last = std::prev(v.end());
std::ostringstream st;
st << "[ ";
std::copy( v.begin(), last, std::ostream_iterator<T>(st,", ") );
st << *last << " ]";
return st.str();
}
A little bit faster version
template <typename T> std::string vectorToString( const std::vector<T>& vec ) {
if ( vec.empty() ) {
return "[]";
}
std::ostringstream s;
s << "[" << vec.front();
for (auto i = vec.begin() + 1, e = vec.end(); i != e; i++)
{
s << ", " << *i;
}
s << "]";
return s.str();
}
Another moment: maybe it would be right to specialize this function for strings and quote them, because if a string in vector begins or ends with , it would be hard to understand how many strings was printed.
template <>
std::string vectorToString< std::string >( const std::vector<std::string>& vec ) {
if ( vec.empty() ) {
return "[]";
}
std::ostringstream s;
s << "[" << vec.front();
for (auto i = vec.begin() + 1, e = vec.end(); i != e; i++)
{
s << ", \"" << *i << "\"";
}
s << "]";
return s.str();
}
Related
The below method will concatenate all warnings into one string. It works but obviously need to create almost the same method again for info and error.
struct MyItem
{
std::vector<std::string> errors;
std::vector<std::string> warnings;
std::vector<std::string> infos;
};
std::vector<MyItem> items;
std::string GetWarnings()
{
std::string str;
for (auto item : items)
{
for (auto warn : item.warnings)
{
str += warn;
str += " ";
}
}
return str;
}
What would be a good generic way to implement one "Concatenate" method? One solution would be to define an enum (error\warning\item), pass it as input argument and make a switch case on argument value. Any more elegant solutions?
You can use a pointer to member to extract a specific field from an object:
auto concatenate(
const std::vector<MyItem>& items,
const std::vector<std::string> MyItem::* member
) {
std::string str;
for (const auto& item : items) {
for (const auto& element : item.*member) {
str += element;
str += " ";
}
}
return str;
}
Which can be used like so:
int main() {
std::vector<MyItem> items{
{{"err11", "err12"}, {"w11"}, {"i11", "i12", "i13"}},
{{"err21"}, {"w21", "w22", "w23", "w24"}, {"i21"}}
};
std::cout << "all errors: " << concatenate(items, &MyItem::errors) << '\n'
<< "all warnings: " << concatenate(items, &MyItem::warnings) << '\n'
<< "all infos: " << concatenate(items, &MyItem::infos) << '\n';
}
And, if you have members of different types in your struct (note that the above solution works only for vectors of strings), you can turn concatenate into a function template:
struct MyItem {
std::vector<std::string> errors;
std::vector<std::string> warnings;
std::vector<std::string> infos;
std::vector<char> stuff; // added
};
template <typename T> // now a function template
auto concatenate(
const std::vector<MyItem>& items,
const T MyItem::* member
) {
std::string str;
for (const auto& item : items) {
for (const auto& element : item.*member) {
str += element;
str += " ";
}
}
return str;
}
int main() {
std::vector<MyItem> items{
{{"err11", "err12"}, {"w11"}, {"i11", "i12", "i13"}, {'1' ,'2'}},
{{"err21"}, {"w21", "w22", "w23", "w24"}, {"i21"}, {'3'}}
};
std::cout << "all errors: " << concatenate(items, &MyItem::errors) << '\n'
<< "all warnings: " << concatenate(items, &MyItem::warnings) << '\n'
<< "all infos: " << concatenate(items, &MyItem::infos) << '\n'
<< "all stuffs: " << concatenate(items, &MyItem::stuff) << '\n';
}
Note that I also changed your auto item occurrences in your for() loops to const auto& items in order to avoid unncecessary copies.
Alternatively, you can use a projection to extract your elements. In this implementation, we use a template to accept any type of a function that will take your MyItem and return the desired element:
template <typename Proj>
auto concatenate(
const std::vector<MyItem>& items,
Proj projection
) {
std::string str;
for (const auto& item : items) {
for (const auto& element : projection(item)) {
str += element;
str += " ";
}
}
return str;
}
int main() {
std::vector<MyItem> items{
{{"err11", "err12"}, {"w11"}, {"i11", "i12", "i13"}, {'1' ,'2'}},
{{"err21"}, {"w21", "w22", "w23", "w24"}, {"i21"}, {'3'}}
};
auto errors_projection =
[](const MyItem& item) -> const std::vector<std::string>& {
return item.errors;
};
auto warnings_projection =
[](const MyItem& item) -> const std::vector<std::string>& {
return item.warnings;
};
auto infos_projection =
[](const MyItem& item) -> const std::vector<std::string>& {
return item.infos;
};
auto stuff_projection =
[](const MyItem& item) -> const std::vector<char>& {
return item.stuff;
};
std::cout << "all errors: " << concatenate(items, errors_projection) << '\n'
<< "all warnings: " << concatenate(items, warnings_projection) << '\n'
<< "all infos: " << concatenate(items, infos_projection) << '\n'
<< "all stuffs: " << concatenate(items, stuff_projection) << '\n';
}
I want to print the vector dicVec in order to check if everything is as I want. But I can´t. I already looked it up, but nothing helped.
This is my current code:
void Translate::read(){
int i = 0;
std::ifstream dic("ende.dic");
if (dic.is_open())
{
std::string dicLine;
while (std::getline(dic, dicLine)){
std::vector<std::pair<std::string, std::string>> dicVec;
std::pair<std::string, std::string> dicPair;
std::size_t pos = dicLine.find(";");
dicPair.first = dicLine.substr(0, pos);
//std::cout << dicPair.first << " : ";
dicPair.second= dicLine.substr(pos+1);
//std::cout << dicPair.second << std::endl;
std::cout << dicVec[i];
i++;
}
}
else {
throw std::runtime_error("File could not be opened");
}
}
I also tried to print it using this:
std::cout << dicVec.at(i);
and this:
for (auto i = dicVec.begin(); i != dicVec.end(); ++i)
std::cout << *i << ' ';
But there´s always this error:
no match for operator<<
What do I have to do in order to print my vector?
Thank you for your help.
You are trying to print out a std::pair, but there is no standard operator<< implemented for std::pair, so you will have to write you own.
Even if you fix that, your code will still fail, because dicVec is empty when you call std::cout << dicVec[i]; You are not adding dicPair to dicVec before printing the contents of dicVec. In fact, dicVec should be declared above the loop, not inside of it.
Try something more like this:
typedef std::pair<std::string, std::string> stringPair;
typedef std::vector<stringPair> stringPairVec;
std::ostream& operator<<(std::ostream &out, const stringPair &p) {
out << p.first << " : " << p.second << "\n";
return out;
}
std:ostream& operator<<(std::ostream &out, const stringPairVec &vec) {
for (size_t i = 0; i < vec.size(); ++i) {
out << vec[i];
}
return out;
}
void Translate::read(){
std::ifstream dic("ende.dic");
if (!dic.is_open()) {
throw std::runtime_error("File could not be opened");
}
stringPairVec dicVec;
std::string dicLine;
while (std::getline(dic, dicLine)) {
std::size_t pos = dicLine.find(";");
stringPair dicPair = std::make_pair(
dicLine.substr(0, pos),
dicLine.substr(pos+1)
);
dicVec.push_back(dicPair);
}
std::cout << dicVec;
}
Or, in C++11 and later, you can do this instead:
using stringPair = std::pair<std::string, std::string>;
using stringPairVec = std::vector<stringPair>;
std::ostream& operator<<(std::ostream &out, const stringPair &p) {
out << p.first << " : " << p.second << "\n";
return out;
}
std:ostream& operator<<(std::ostream &out, const stringPairVec &vec) {
for (const auto &p : vec) {
out << p;
}
return out;
}
void Translate::read(){
std::ifstream dic("ende.dic");
if (!dic.is_open()) {
throw std::runtime_error("File could not be opened");
}
stringPairVec dicVec;
std::string dicLine;
while (std::getline(dic, dicLine)) {
std::size_t pos = dicLine.find(";");
dicVec.emplace_back(
dicLine.substr(0, pos),
dicLine.substr(pos+1)
);
}
std::cout << dicVec;
}
I've only found some answers to this problem in Python and JS, hopefully you can help me to do the same in c++.
So the challenge is to print out the first recurring character of a given string, here is what i came up with, but I don't know if this code actually looks good. This is my first time posting on StackOverflow, hopefully I'll get some feedback =)
#include <iostream>
#include <vector>
int main() {
std::cout << "Enter some letters:\n";
std::string str;
std::cin >> str;
// vector that stores characters that we will come across in the string
std::vector<char> seen(0);
for (char a : str) {
for (int i = 0; i < seen.size(); i++) {
if (a == seen[i]) {
std::cout << a << std::endl;
return 0;
} else { continue; }
}
seen.push_back(a);
}
std::cout << "none\n";
return 0;
}
For speed, how about:
#include <iostream>
int main() {
std::cout << "Enter some letters:\n";
std::string str;
std::cin >> str;
bool seen [256] = { };
for (char a : str) {
unsigned char u = (unsigned char) a;
if (seen [u]) {
std::cout << a << std::endl;
return 0;
}
seen [u] = true;
}
std::cout << "none\n";
return 0;
}
This is O(N), rather than O(N*N/2)
Live demo
For your task check out std::find:
void printRecurring(const std::string& str) {
std::string::const_iterator it = str.begin(), e = str.end();
for (std::string::const_iterator it2 = str.begin(); it2 != str.end(); ++it2) {
it = std::find(it + 1, e, *it2);
if (it != str.end()) {
std::cout << *it2 << std::endl;
return;
}
}
}
I think you can make it a little simpler by using std::find.
#include <iostream>
#include <vector>
#include <algoritm>
int main()
{
std::cout << "Enter some letters:\n";
std::string str;
std::cin >> str;
// vector that stores characters that we will come across in the string
std::vector<char> seen(0);
for (char a : str) {
auto it = std::find(seen.begin(), seen.end(), a);
if (it != seen.end()) {
std::cout << "Found it: " << *it << std::endl;
return 0;
}
seen.push_back(a);
}
std::cout << "none\n";
return 0;
}
I've a class withmap<string,vector<string>>.
I want to give a user a member function to receive the value for a key in different formats than std::vector(string):
vector(string),
string,
vector(int),
vector(float) and
bool
example:
bool x = (bool) myClass["dummy_boolean_type"]
x = myClass["dummy_boolean_type"].as<bool>
int y = (int) myClass["dummy_boolean_type"]
Can someone have an example what is the best way to achieve it ?
(without a use in Boost)
You cannot provide your class with any member function or functions
that will support the two constructions you want:
T x = myClassInstance["key"].as<T> // (1)
T x = (T) myClassInstance["key"] // (2)
In the case of (1), the immediate reason is simply that the construction is
not legal C++. So let's suppose it is replaced by:
T x = myClassInstance["key"].as<T>() // (1a)
But this doesn't help, and the reason is the same for both (1a) and (2):
The expression myClassInstance["key"] will have to evaluate to some object e or reference to such that is returned by:
myClass::operator[](std::string const &);
This e is the vector<string> to which key maps in your
map<string,vector<string> data member of myClass. It is not myClassInstance.
So what you are asking for are member functions of myClass that will support
the constructions:
T x = e.as<T> // (1b)
T x = (T) e // (2b)
where e is an std::vector<std::string>.
Clearly, nothing you can do in myClass can address your requirement. In
(1b) and (2b), myClass is nowhere to be seen.
Is there any template member function of std::vector<std::string>:
template<typename T>
T as() const;
that has the behaviour you want for (1b)?
Does std::vector<std::string> have any template member function:
template<typename T>
operator T() const;
that has the behaviour you want for (2b)?
No and No.
However...
You can implement an as template member function of myClass that
supports conversions such as you mention. Its signature - of course -
would be:
template<typename T>
T myClass::as(std::string const & key) const;
and you would invoke it like:
T x = myClassInstance.as<T>("key") // (1c)
I'll sketch an implemention that assumes we're content with the
conversions from std::vector<std::string> to:
std::string
std::vector<int>
bool
which will be enough to get you under way.
To convert an std::vector<std::string> vs to std::string I'll concatenate
the elements of vs.
To convert an std::vector<std::string> vs to std::vector<int> I'll convert each element of vs from a decimal numeral, if I can, to the
integer the numeral represents, and return a vector of those integers. Without
prejudice to other policies I'll throw an std::invalid_argument exception
when an element doesn't trim to a decimal numeral.
I am spoilt for choice as to what you might mean by converting an std::vector<std::string>
to bool, so I will arbitrarily say that vs is true if I can convert it
to a vector<int> of which any element is non-0 and is false if I can convert
it to a vector<int> in which all elements are 0.
The sketch:
#include <type_traits>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
namespace detail {
template<typename T>
struct convert_to
{
static T from(std::vector<std::string> const & vs) {
static constexpr bool always_false = !std::is_same<T,T>::value;
static_assert(always_false,
"Calling `convert_to<T>::from` for unimplemented `T`");
return *(T*)nullptr;
}
};
template<>
std::string convert_to<std::string>::from(std::vector<std::string> const & vs)
{
std::string s;
for ( auto const & e : vs ) {
s += e;
}
return s;
}
template<>
std::vector<int>
convert_to<std::vector<int>>::from(std::vector<std::string> const & vs)
{
auto lamb = [](std::string const & s) {
std::size_t lastoff = s.find_last_not_of(" \t\f\v\n\r");
int i;
try {
std::size_t nlen;
i = std::stoi(s,&nlen);
if (nlen <= lastoff) {
throw std::invalid_argument("");
}
}
catch(std::invalid_argument const & e) {
throw std::invalid_argument(
"Cannot convert \"" + s + "\" to int");
}
return i;
};
std::vector<int> vi;
std::transform(vs.begin(),vs.end(),std::back_inserter(vi),lamb);
return vi;
}
template<>
bool convert_to<bool>::from(std::vector<std::string> const & vs)
{
auto vi = convert_to<std::vector<int>>::from(vs);
for (auto const & i : vi) {
if (i) {
return true;
}
}
return false;
}
} // namespace detail
struct myClass // Your class
{
// Whatever...
std::vector<std::string> & operator[](std::string const & key) {
return _map[key];
}
template<typename T>
T as(std::string const & key) {
return detail::convert_to<T>::from(_map[key]);
}
// Whatever...
private:
std::map<std::string,std::vector<std::string>> _map;
};
The one take-away point here is the use of template<typename T>
detail::struct convert_to, with its solitary static member function:
T from(std::vector<std::string> const & vs)
which in the default instantiation will provoke a static_assert failure
reporting that no conversion to T from std::vector<std::string> has been
defined.
Then, for each type U to which you want a conversion, you have just to
write a specializing definition:
template<>
U convert_to<U>::from(std::vector<std::string> const & vs);
as you see fit, and the construction (1c) will use it as per:
template<typename T>
T myClass::as(std::string const & key) {
return detail::convert_to<T>::from(_map[key]);
}
Here's an illustrative progam you can append to the sketch:
#include <iostream>
using namespace std;
template<typename T>
static void print_vec(std::vector<T> const & v)
{
cout << "{ ";
for (auto const & e : v) {
cout << e << " ";
}
cout << "}\n";
}
static void print_vec(std::vector<std::string> const & v)
{
cout << "{ ";
for (auto const & e : v) {
cout << '\"' << e << "\" ";
}
cout << "}\n";
}
int main()
{
myClass f;
f["int_vec"] = vector<string>{"0","1 "," 2"};
cout << "f[\"int_vec\"] = "; print_vec(f["int_vec"]);
f["true_vec"] = vector<string>{"0"," 1 ","0"};
cout << "f[\"true_vec\"] = "; print_vec(f["true_vec"]);
f["false_vec"] = vector<string>{"0"," 0","0 "};
cout << "f[\"false_vec\"] = "; print_vec(f["false_vec"]);
f["not_int_vec0"] = vector<string>{"0","1","2",""};
cout << "f[\"not_int_vec0\"] = "; print_vec(f["not_int_vec0"]);
f["not_int_vec1"] = vector<string>{"0","#","2",};
cout << "f[\"not_int_vec1\"] = "; print_vec(f["not_int_vec1"]);
f["not_int_vec2"] = vector<string>{"0"," 1$","2",};
cout << "f[\"not_int_vec2\"] = "; print_vec(f["not_int_vec2"]);
cout << "f.as<string>(\"int_vec\") = \""
<< f.as<string>("int_vec") << '\"' << endl;
cout << "f.as<string>(\"true_vec\") = \""
<< f.as<string>("true_vec") << '\"' << endl;
cout << "f.as<string>(\"false_vec\") = \""
<< f.as<string>("false_vec") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec0\") = \""
<< f.as<string>("not_int_vec0") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec1\") = \""
<< f.as<string>("not_int_vec1") << '\"' << endl;
cout << "f.as<string>(\"not_int_vec2\") = \""
<< f.as<string>("not_int_vec2") << '\"' << endl;
vector<int> va = f.as<vector<int>>("int_vec");
cout << "f.as<vector<int>>(\"int_vec\") = ";
print_vec(f.as<vector<int>>("int_vec"));
cout << boolalpha << "f.as<bool>(\"true_vec\") = "
<< f.as<bool>("true_vec") << endl;
cout << boolalpha << "f.as<bool>(\"false_vec\") = "
<< f.as<bool>("false_vec") << endl;
try {
cout << "f.as<vector<int>>(\"not_int_vec0\")...";
auto b = f.as<vector<int>>("not_int_vec0");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
try {
cout << "f.as<vector<int>>(\"not_int_vec1\")...";
auto b = f.as<vector<int>>("not_int_vec1");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
try {
cout << "f.as<vector<int>>(\"not_int_vec2\")...";
auto b = f.as<vector<int>>("not_int_vec2");
(void)b;
}
catch(std::invalid_argument const & e) {
cout << e.what() << endl;
}
// char ch = f.as<char>("int_vec"); <- static_assert fails
return 0;
}
It outputs:
f["int_vec"] = { "0" "1 " " 2" }
f["true_vec"] = { "0" " 1 " "0" }
f["false_vec"] = { "0" " 0" "0 " }
f["not_int_vec0"] = { "0" "1" "2" "" }
f["not_int_vec1"] = { "0" "#" "2" }
f["not_int_vec2"] = { "0" " 1$" "2" }
f.as<string>("int_vec") = "01 2"
f.as<string>("true_vec") = "0 1 0"
f.as<string>("false_vec") = "0 00 "
f.as<string>("not_int_vec0") = "012"
f.as<string>("not_int_vec1") = "0#2"
f.as<string>("not_int_vec2") = "0 1$2"
f.as<vector<int>>("int_vec") = { 0 1 2 }
f.as<bool>("true_vec") = true
f.as<bool>("false_vec") = false
f.as<vector<int>>("not_int_vec0")...Cannot convert "" to int
f.as<vector<int>>("not_int_vec1")...Cannot convert "#" to int
f.as<vector<int>>("not_int_vec2")...Cannot convert " 1$" to int
(gcc 5.1, clang 3.6, C++11)
I am wondering if there is way that std::cout automatically will insert some predefined value between printed sequences.
For example:
std::cout << 2 << 3 << 33 << 45 << std::endl;
outputs
233345
and I would like it to output
2 3 33 45
and I know, that it's easy to:
std::cout << 2 << " " << 3 << " " << 33 << " " << 45 << std::endl;
But I'am wondering if there is a way to automate this, such as:
std::cout << set_some_separator(" ") << 2 << 3 << 33 << 45 << std::endl;
Anyone aware of something like this being possible?
Well, I got beaten to it. I'll post this anyway.
Edit : well, after reading Nim's answer, mine does achieve the exact syntax OP wished for.
#include <iostream>
#include <algorithm>
struct with_separator {
with_separator(std::string sep)
: sep(std::move(sep)) {}
std::string sep;
};
struct separated_stream {
separated_stream(std::ostream &stream, std::string sep)
: _stream(stream), _sep(std::move(sep)), _first(true) {}
template <class Rhs>
separated_stream &operator << (Rhs &&rhs) {
if(_first)
_first = false;
else
_stream << _sep;
_stream << std::forward<Rhs>(rhs);
return *this;
}
separated_stream &operator << (std::ostream &(*manip)(std::ostream&)) {
manip(_stream);
return *this;
}
private:
std::ostream &_stream;
std::string _sep;
bool _first;
};
separated_stream operator << (std::ostream &stream, with_separator wsep) {
return separated_stream(stream, std::move(wsep.sep));
}
int main()
{
std::cout << with_separator(", ") << 1 << 2 << 3 << std::endl;
}
Output :
1, 2, 3
Simple answer is No, however, you can roll your own...
#include <iostream>
#include <sstream>
using namespace std;
struct set_some_separator{
set_some_separator(const char* sep) : _sep(sep)
{ };
template <typename T>
set_some_separator& operator<<(const T& v)
{
_str << v << _sep;
return *this;
}
friend
ostream& operator<<(ostream& os, const set_some_separator& s)
{ return os << s._str.str(); }
const char* _sep;
ostringstream _str;
};
int main()
{
cout << (set_some_separator(" ") << 2 << 3 << 33 << 45) << endl;
}
Okay the format of the cout is slightly different, hey-ho...
Not quite the same thing, but:
#include <array>
#include <iostream>
#include <iterator>
int main() {
std::array<int, 3> data = { 1, 2, 3 };
std::ostream_iterator<int> out(std::cout, " ");
std::copy(data.begin(), data.end(), out);
std::cout << '\n';
return 0;
}
How about using the ostream_iterator
int main()
{
std::vector<int> data {2,3,33,45};
std::copy(std::begin(data), std::end(data),
std::ostream_iterator(std::cout, " "));
std::cout << "\n";
}
A C++17 fold expression with the comma operator can create a nice one-liner:
[](auto &&...xs){ ((std::cout << xs << ',') , ...); }(2,3,33,45);
Simple solution, maybe you can tweak it to use <<
template<typename T>
void myout(T value)
{
std::cout << value << std::endl;
}
template<typename First, typename ... Rest>
void myout(First first, Rest ... rest)
{
std::cout << first << " ";
myout(rest...);
}
myout('a',"Hello",1,2,3,22/7.0);
If you're just looking for a way to print a vector with its elements properly delimited (and without an extra delimiter at the end), try this:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3};
auto it = v.begin();
if (it != v.end())
{
std::cout << *it;
++it;
}
for (; it != v.end(); ++it)
{
std::cout << ", " << *it;
}
}