Why does ostream_iterator not work as expected?
The problem is that the name lookup does not find your operator<<(ostream& os, const PAIR& r)
. The code that tries to invoke the operator<<
is in somewhere inside the ostream_iterator<>
which is itself inside the std
namespace. The name lookup looks around for the right function inside ostream_iterator<>
and the std
namespace; the argument dependent lookup does not help here because both of the parameters are in the std
namespace, too.
So, my suggestion is (1) either to wrap your operator into namespace std { }
, but that is UB, IIRC. Or (2) create a struct inheriting from std::pair
to define a new type in your namespace, and using the ADL to find your operator<<()
.
UPDATE:
My 3rd suggestion is to use a custom manipulator to print out the pair.
As for my 2nd suggestion, if you can use C++11, inheriting from std::pair
should be easy (untested):
struct PAIR : std::pair
{
using std::pair::pair;
};
If you cannot use C++11, then I suggest using a custom manipulator.
std::ostream_iterator does not find operator
std::copy
cannot find overloading for operator <<
for std::pair
in std
namespace. There is no good way, to overload operator <<
for object from std
namespace in algorithms from std
namespace.
You can use std::for_each
with functor, that will print your values, for example with lambda.
std::for_each(data.begin(), data.end(), [](const std::pair<int, int>& p)
{
std::cout << p << std::endl;
});
You cannot put overloading in std namespace, you can only add specializations for user-defined types since
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a
namespace within namespace std unless otherwise specifiedA program may add a template specialization
for any standard library template to namespace std only if the declaration depends on a user-defined type
and the specialization meets the standard library requirements for the original template and is not explicitly
prohibited.
template argument for ostream_iterator-each element is pair
There is NO operator <<
for std::pair
. You cannot simply use ostream_iterator
with std::pair
.
You can use other things, or write class, that derived from pair
, or that store pair
and use it. You cannot write overloads in std
namespace, since it leads to undefined behaviour and you cannot overload this operator in global namespace, since ADL
will not find correct overload (if you use stl algorithms, like copy
, ostream_iterator
).
Simply, something like this will work well
#include <iostream>
#include <utility>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<std::pair<int, int>> vec =
{
{1,1},
{2,2}
};
for (const auto& p : vec)
{
std::cout << p.first << " " << p.second << std::endl;
}
}
Dereferencing and increment with ostream_iterator
Conceptually, when writing to a range, you'd want to move to the next element after writing to one. For most iterators, like e.g. a std::vector::iterator
, that has to be done explicitly. So it kind of makes sense to include it, if only for consistency.
In the particular case of std::ostream_iterator
, it does not have an actual effect though, and could be left out. You cannot overwrite an "element" of the output range anyways, advancing is implicit (and only implicit, i.e. both the increment operators as well as derefencing are no-ops in this context).
The important part is only the operator =
, as explained in the relevant documentation:
#include <iostream>
#include <iterator>
int main()
{
std::ostream_iterator<int> i1(std::cout, ", ");
*i1++ = 1; // usual form, used by standard algorithms
*++i1 = 2;
i1 = 3; // neither * nor ++ are necessary
std::ostream_iterator<double> i2(std::cout);
i2 = 3.14;
}
Why can't I instantiate operator (ostream&, vector T &) with T=vector int ?
Two words: name lookup.
Here is a simplified example of what you are trying to do, without any Standard Library headers required:
template <typename T> void f(T) { }
namespace ns {
class C { };
void f(int) { }
void test() { f(C()); } // doesn't work :'(
}
int main() {
f(ns::C()); // works! :-D
}
In this example, in main()
, the only f
that is found during normal name lookup is the function template in the global namespace, and it matches, so main
uses it (ns::f
is also found during argument-dependent lookup, but it isn't a match so the global f
is still selected during overload resolution).
In test
, however, the ns::f(int)
overload is found and name lookup stops. Namespaces are searched outwards, so ns
is searched first, then the global namespace, but name lookup stops once a name is found, so once ns::f(int)
is found, name lookup stops. Argument-dependent lookup also takes place and also finds ns::f(int)
, since C
is in namespace ns
, then ADL stops searching.
The same is true in your example: in main()
, the operator<<
overload is found, but inside of the std::ostream_iterator
, which is in the std
namespace, other <<
overloads are found, and so your overload is not found.
Your operator<<
overload would need to be in the std
namespace for it to work, but unfortunately you aren't allowed to add names to the std
namespace.
Overload for ostream on vectors throws error when using std::copy
Because your operator<<
is not visible to std
entities.
Note std::ostream_iterator<T>
outputs values as if through operator<<
, and according to [temp.dep.res]/1:
In resolving dependent names, names from the following sources are
considered:
- Declarations that are visible at the point of definition of the template.
- Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point])
and from the definition context.
... your operator<<
is neither visible at the point of definition of std::ostream_iterator<T>
, nor in the namespace std
, so the operator<<
used in std::ostream_iterator<T>
cannot be correctly resolved.
ostream_iterator for Binary Output
It works, but you will have to explicitely use an ostream_iterator<char>
.
Example (includes omitted for brievety):
int main(int argc, char **argv) {
std::vector<int> arr;
std::ofstream fd("foo.txt", std::ios::binary | std::ios::out);
for (int i=0; i<256; i++) arr.push_back(i);
std::ostream_iterator<char> oi(fd);
std::copy(arr.begin(), arr.end(), oi);
fd.close();
return 0;
}
will write the 256 bytes for 0 to 255 in foo.txt.
Above assumed that you wanted to write directly the value of the int as a char to the file. From your comment, you want to write the int value as a 4 bytes value (assuming int32_t) in native host endianness. I would use an auxilliary class to do the job:
class bint {
private:
char c[sizeof(int)];
public:
bint(const int i) { // allows bint b = 5;
::memcpy(c, &i, sizeof(c));
}
operator int() const { // allows : bint b = 5; int i=b => gives i=5
int i;
::memcpy(&i, c, sizeof(int));
return i;
}
const char *getBytes() const { // gives public read-only access to the bytes
return c;
}
};
std::ostream& operator <<(std::ostream& out, const bint& b) {
out.write(b.getBytes(), sizeof(int));
return out;
}
int main(int argc, char **argv) {
std::vector<int> arr;
std::ofstream fd("foo.txt", std::ios::binary | std::ios::out);
for (int i=0; i<256; i++) arr.push_back(i);
std::ostream_iterator<bint> oi(fd);
std::copy(arr.begin(), arr.end(), oi);
fd.close();
return 0;
}
This one writes 1024 bytes (for integer of size 4) containing the representations of the 256 first integers. It would automatically adapts to other sizes of int.
STL remove doesn't work as expected?
Actually std::remove
doesn't remove the item from the container. Quoted from here
Remove removes from the range
[first, last)
all elements that are equal tovalue
. That is, remove returns an iteratornew_last
such that the range[first, new_last)
contains no elements equal tovalue
. The iterators in the range[new_last, last)
are all still dereferenceable, but the elements that they point to are unspecified. Remove is stable, meaning that the relative order of elements that are not equal to value is unchanged.`
That is, std::remove
works with a pair of iterators only and does not know anything about the container which actually contains the items. In fact, it's not possible for std::remove
to know the underlying container, because there is no way it can go from a pair of iterators to discover about the container to which the iterators belong. So std::remove
doesn't really remove the items, simply because it cannot. The only way to actually remove an item from a container is to invoke a member function on that container.
So if you want to remove the items, then use Erase-Remove Idiom:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
The erase-remove idiom is so common and useful is that std::list
has added another member function called list::remove
which produces the same effect as that of the erase-remove
idiom.
std::list<int> l;
//...
l.remove(10); //it "actually" removes all elements with value 10!
That means, you don't need to use erase-remove
idiom when you work with std::list
. You can directly call its member function list::remove
.
Related Topics
Splitting a String by a Character
C++ #Include <Atlbase.H> Is Not Found
Unordered_Map Hash Function C++
Does Std::Vector *Have* to Move Objects When Growing Capacity? Or, Can Allocators "Reallocate"
Can a Bool Read/Write Operation Be Not Atomic on X86
Opengl Define Vertex Position in Pixels
Static Constexpr Member of Same Type as Class Being Defined
Sorting Two Corresponding Arrays
What's a Use Case for Overloading Member Functions on Reference Qualifiers
Waitpid Equivalent with Timeout
In What Ways Do C++ Exceptions Slow Down Code When There Are No Exceptions Thown
Class Variables: Public Access Read-Only, But Private Access Read/Write
How to Generate a Random Double Uniformly Distributed Between 0 and 1 from C++