Re: reading and writing a container of std::pair type
 
* On Feb 18, 10:54 am, Gil <vnic...@gmail.com> wrote:
On Feb 17, 9:25 am, "V.Subramanian, India"
<subramanian10...@yahoo.com> wrote:
Consider the following program x.cpp:
using namespace std;
typedef pair<int, string> pair_type;
7.1.3 [dcl.typedef] /1 "A typedef-name is thus a synonym for another
type.
A typedef-name does not introduce a new type"[...]
your pair_type is a std:: namespace type name.
int main()
{
    istream_iterator<pair_type> ii(cin);
24.6.1.1 [istream.iterator.cons] /3
istream_iterator(istream_type& s);
3 Effects: Initializes in_stream with &s.
value may be initialized during construction or the first time
it is referenced.[...]
inplementations are allowed (but not forced) to use extractor
in initialization. when implementation evaluates expression
*in_stream >> value
it does it in a context of an argument dependent call in the scope
of std::istream_iterator thus it will search first the most inner
scope for a suitable operator >>.
none are found.
then it does 3.4.2 [basic.lookup.argdep] but associated namespaces
for both arguments are namespace std:: as well.
your user defined operator in global scope is never found.
note: it should be found if you do something like
pair_type myp;
cin >> myp;
through ordinary lookup.
the key to understand the issue is pair_type is a std:: type and
it is not associated with your operator's scope.
3.4.2 [basic.lookup.argdep] /2
[...]Typedef names and using-declarations used to specify the types
do not contribute to this set.[...]
the clean solution imo is to use your own data type instead of
std::pair.
hth,
gil
Thanks for your help.
I checked the ISO C++ Standard document for the section
3.4.2. But I am unable to understand the Standard document.
However I understodd from your reply that my operator<<
and operator>> are not considered for the reasons stated by
you. Also as advised by you, I have attempted to write a class
wrapping pair<T, U>. The program compiles fine and
works as expected. Here is the program x.cpp:
#include <cstdlib>
#include <iostream>
#include <ostream>
#include <string>
#include <utility>
#include <iterator>
#include <vector>
#include <algorithm>
#include <list>
using namespace std;
template <typename T, typename U>
class ExtractorInsertor {
public:
   ExtractorInsertor(const pair<T, U>& arg =
                     make_pair(T(), U()));
   ExtractorInsertor(const ExtractorInsertor& rhs);
   ExtractorInsertor& operator=(
                        const ExtractorInsertor& rhs);
   ~ExtractorInsertor();
   T first() const;
   void first(const T& arg);
   U second() const;
   void second(const U& arg);
   istream& readFrom(istream& in);
   ostream& writeTo(ostream& out) const;
private:
   pair<T, U> pairVal;
};
template <typename T, typename U>
inline ExtractorInsertor<T, U>::ExtractorInsertor(
          const pair<T, U>& arg) : pairVal(arg)
{
}
template <typename T, typename U>
inline ExtractorInsertor<T, U>::ExtractorInsertor(
          const ExtractorInsertor& rhs) :
                pairVal(rhs.pairVal)
{
}
template <typename T, typename U>
inline ExtractorInsertor<T, U>&
       ExtractorInsertor<T, U>::operator=(
            const ExtractorInsertor& rhs)
{
   if (this != &rhs)
      pairVal = rhs.pairVal;
   return *this;
}
template <typename T, typename U>
inline ExtractorInsertor<T, U>::~ExtractorInsertor()
{
}
template <typename T, typename U>
inline T ExtractorInsertor<T, U>::first() const
{
   return pairVal.first;
}
template <typename T, typename U>
inline void ExtractorInsertor<T, U>::first(
                      const T& arg)
{
   pairVal.first = arg;
   return;
}
template <typename T, typename U>
inline U ExtractorInsertor<T, U>::second() const
{
   return pairVal.second;
}
template <typename T, typename U>
inline void ExtractorInsertor<T, U>::second(
                         const U& arg)
{
   pairVal.second = arg;
   return;
}
template <typename T, typename U>
inline istream& ExtractorInsertor<T, U>::readFrom(
                        istream& in)
{
   T first;
   U second;
   if (in >> first >> second)
      pairVal = make_pair(first, second);
   return in;
}
template <typename T, typename U>
inline ostream& ExtractorInsertor<T, U>::writeTo(
                           ostream& out) const
{
   return out << pairVal.first
              << "  "
              << pairVal.second
              << endl;
}
template <typename T, typename U>
inline istream& operator>>(
             istream& in,
             ExtractorInsertor<T, U>& arg)
{
   return arg.readFrom(in);
}
template <typename T, typename U>
inline ostream& operator<<(
            ostream& out,
            const ExtractorInsertor<T, U>& arg)
{
   return arg.writeTo(out);
}
int main()
{
   typedef ExtractorInsertor<int, string> pairTypeOne;
   istream_iterator<pairTypeOne> ii(cin);
   istream_iterator<pairTypeOne> eos;
   typedef vector<pairTypeOne> Container;
   Container v(ii, eos);
   cout << "-----------------------------" << endl;
   copy(v.begin(),
        v.end(),
        ostream_iterator<Container::value_type>(
          cout));
   cout << "-----------------------------" << endl;
   typedef ExtractorInsertor<string, double> pairTypeTwo;
   istream_iterator<pairTypeTwo> iiAnother(cin);
   istream_iterator<pairTypeTwo> eosAnother;
   typedef list<pairTypeTwo> ContainerAnother;
   ContainerAnother c(iiAnother, eosAnother);
   cout << "-----------------------------" << endl;
   copy(c.begin(),
        c.end(),
        ostream_iterator<ContainerAnother::value_type>(
                      cout));
   return EXIT_SUCCESS;
}
Is this solution correct ? The problem with the
templatized version is that if ExtractorInsertor has
pointer argument types, then copy ctor and copy-assignment
   void first(const T& arg);
   void second(const U& arg);
will not work correctly because they will just assign
the pointer values. Am I correct ? For this scenario, can
I write specialized versions of ExtractorInsertor with the
appropriate pointer argument types and the affected member
functions beging modified suitably ?
Please explain.
Thanks
V.Subramanian