insertion operator and namespace?

P

Patrick Guio

Dear all,

I have some problem with insertion operator together with namespace.
I have a header file foo.h containing declaration of classes, typedefs and
insertion operators for the typedefs in a named namespace

namespace foo
{

class Foo
{
typedef std::vector<unsigned char> Vec;
typedef std::vector<Key> VecVec;
....

};

std::eek:stream & operator<<(std::eek:stream &os, const Foo::Vec &v);
std::eek:stream & operator<<(std::eek:stream &os, const Foo::VecVec &v);

}

Then the definition in the file foo.cc

namespace foo
{

std::eek:stream & operator<<(std::eek:stream &os, const Foo::Vec &v)
{
...
}
std::eek:stream & operator<<(std::eek:stream &os, const Foo::VecVec &v)
{
}

}

Now I would like to use the insertion operators in a programm. If the
program looks like

#include "foo.h"

int main()
{
Foo::Vec vec;
Foo::VecVec vecs;

....

// "using namespace" directive required
// otherwise compiler get confused with
// other available insertions in std::
{
using namespace foo;
std::cout << vec << std::endl;
std::cout << vecs << std::endl;
}
}

I wonder how to avoid using the using namespace directive?

Sincerely,

Patrick
 
B

Bob Hairgrove

Dear all,

I have some problem with insertion operator together with namespace.
I have a header file foo.h containing declaration of classes, typedefs and
insertion operators for the typedefs in a named namespace

namespace foo
{

class Foo
{
typedef std::vector<unsigned char> Vec;
typedef std::vector<Key> VecVec;
....

};

std::eek:stream & operator<<(std::eek:stream &os, const Foo::Vec &v);
std::eek:stream & operator<<(std::eek:stream &os, const Foo::VecVec &v);

}

Then the definition in the file foo.cc

namespace foo
{

std::eek:stream & operator<<(std::eek:stream &os, const Foo::Vec &v)
{
...
}
std::eek:stream & operator<<(std::eek:stream &os, const Foo::VecVec &v)
{
}

}

Now I would like to use the insertion operators in a programm. If the
program looks like

#include "foo.h"

int main()
{
Foo::Vec vec;
Foo::VecVec vecs;

....

// "using namespace" directive required
// otherwise compiler get confused with
// other available insertions in std::
{
using namespace foo;
std::cout << vec << std::endl;
std::cout << vecs << std::endl;
}
}

I wonder how to avoid using the using namespace directive?

You have to put the overloads for operator<< into the global
namespace, i.e.:

std::eek:stream & operator<<(std::eek:stream &os
, const foo::Foo::Vec &v)
{
...
}
std::eek:stream & operator<<(std::eek:stream &os
, const foo::Foo::VecVec &v)
{
}

What I don't understand is why your earlier declarations compile
without specifying the namespace, i.e.:
#include "foo.h"

int main()
{
Foo::Vec vec;
Foo::VecVec vecs;

This shouldn't compile without a using directive, a using declaration,
or specifying the namespace qualifier explicitly.
 
P

Peter Steiner

#include "foo.h"
int main()
{
Foo::Vec vec;
Foo::VecVec vecs;

how does that compile? class Foo is defined inside a namespace foo in
foo.h, which is not part of the current namespace?
....

// "using namespace" directive required
// otherwise compiler get confused with
// other available insertions in std::
{
using namespace foo;
std::cout << vec << std::endl;
std::cout << vecs << std::endl;
}

}

using the << operator overload for you types requires
argument-dependend lookup because the concerning operator is not
defined in a visible namespace. unfortunately the standard doesn't seem
to define argument-dependend lookup for typedefs, the lookup is still
associated to the concrete type (std::vector in your case).

you could call the operator directly to be able to specify the
namespace explicitely, though you probably wouldn't want to do that:

(foo::eek:perator << (std::cout, vec)) << std::endl;
(foo::eek:perator << (std::cout, vecs)) << std::endl;

maybe you should just define the operator overloads in the global
namespace.

-- peter
 
P

Patrick Guio

On Tue, 8 Nov 2005, Bob Hairgrove wrote:

Hi Bob,

I still have problem which can be summarize in the following code:
You have to put the overloads for operator<< into the global
namespace, i.e.:

std::eek:stream & operator<<(std::eek:stream &os
, const foo::Foo::Vec &v)
{
...
}
std::eek:stream & operator<<(std::eek:stream &os
, const foo::Foo::VecVec &v)
{
}

What I don't understand is why your earlier declarations compile
without specifying the namespace, i.e.:


This shouldn't compile without a using directive, a using declaration,
or specifying the namespace qualifier explicitly.

My fault, this is just a code snippet I made to sketch my problem. Of
course there should foo::Foo::Vec and foo::Foo::VecVec (or a
"using foo::Foo" directive before).

Anyway I still have 2 compilation problems in the following code with
the class Fred in namespace fred.
The compiler (g++ v.4.0.1) complains that
* 'int fred::Fred::i_' is private within the context 'return o << fred.i_;'
* 'std::cout << [snip] << fred << "\n";' is an ambiguous overload
and candidates are:
std::eek:stream& operator<<(std::eek:stream&, const fred::Fred&)
std::eek:stream& fred::eek:perator<<(std::eek:stream&, const fred::Fred&)

Any idea of how to solve these problems?

Sincerely,

Patrick


#include <iostream>

// class in fred namespace
namespace fred
{
class Fred
{
public:
friend std::eek:stream& operator<< (std::eek:stream& o, const fred::Fred& fred);
Fred() : i_(1) {}
~Fred() {}
private:
int i_;
};
}

std::eek:stream& operator<< (std::eek:stream& o, const fred::Fred& fred)
{
return o << fred.i_;
}

int main()
{
fred::Fred fred;
std::cout << "My Fred object: " << fred << "\n";
return 0;
}
 
J

Jonathan Mcdougall

Patrick said:
Anyway I still have 2 compilation problems in the following code with
the class Fred in namespace fred.
The compiler (g++ v.4.0.1) complains that
* 'int fred::Fred::i_' is private within the context 'return o << fred.i_;'
* 'std::cout << [snip] << fred << "\n";' is an ambiguous overload
and candidates are:
std::eek:stream& operator<<(std::eek:stream&, const fred::Fred&)
std::eek:stream& fred::eek:perator<<(std::eek:stream&, const fred::Fred&)

Any idea of how to solve these problems?

Sincerely,

Patrick


#include <iostream>

// class in fred namespace
namespace fred
{
class Fred
{
public:
friend std::eek:stream& operator<< (std::eek:stream& o, const fred::Fred& fred);

This operator's name is actually fred::eek:perator<<().
Fred() : i_(1) {}
~Fred() {}
private:
int i_;
};
}

std::eek:stream& operator<< (std::eek:stream& o, const fred::Fred& fred)

And this one is

std::eek:stream ::eek:perator<<().

Just put the operator in the namespace.
{
return o << fred.i_;

Here you get an error because this operator is not a friend. This
functions is not the same as the one declared as friend in Fred.
}

int main()
{
fred::Fred fred;
std::cout << "My Fred object: " << fred << "\n";
return 0;
}


Jonathan
 
P

Patrick Guio

On Wed, 9 Nov 2005, Jonathan Mcdougall wrote:

Hi Jonathan,

Thank you for your answer. I still wonder whether the following code
snippet could be simplified?
Sincerely, Patrick

namespace foo
{
class Foo
{
public:
typedef std::vector<unsigned char> Vec;
friend std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo & f);
friend std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo::Vec & v);
Foo() : a(3, 5) {};
~Foo() {};
private:
Vec a;
};
}

std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo & f)
{
return os << f.a << std::endl;
}

// insertion operator used by the insertion operator
// std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo & f)
std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo::Vec & v)
{
using foo::Foo;
// code for insertion operator of a std::vector
Foo::Vec::const_iterator i = v.begin(), e = v.end();
// code for insertion operator of a std::vector
.....
}

// insertion operator for object as in the main:
// foo::Foo::Vec a(4, 1);
// std::cout << a << std::endl;
std::eek:stream & operator<<(std::eek:stream &os, const foo::Foo::Vec & v)
{
return foo::eek:perator<<(os , v);
}


int main()
{
foo::Foo f;
std::cout << f << std::endl;

foo::Foo::Vec a(4, 1);
std::cout << a << std::endl;
}
 
P

Patrick Guio

On Wed, 9 Nov 2005, Patrick Guio wrote:

Hi Jonathan,

Maybe I should formulate my question differently. Do I need both insertion
operators (in global and foo namespace) for type foo::Foo::Vec so that it
can be used for private member object of class Foo and also in global
namespace? Can that be simplified to one insertion operator?
Sincerely,
Patrick
Thank you for your answer. I still wonder whether the following code snippet
could be simplified?
Sincerely, Patrick

namespace foo
{
class Foo
{
public:
typedef std::vector<unsigned char> Vec;
friend std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo & f);
friend std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo::Vec & v);
Foo() : a(3, 5) {};
~Foo() {};
private:
Vec a;
};
}

std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo & f)
{
return os << f.a << std::endl;
}

// insertion operator used by the insertion operator
// std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo & f)
std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo::Vec & v)
{
using foo::Foo;
// code for insertion operator of a std::vector
Foo::Vec::const_iterator i = v.begin(), e = v.end();
// code for insertion operator of a std::vector
....
}

// insertion operator for object as in the main:
// foo::Foo::Vec a(4, 1);
// std::cout << a << std::endl;
std::eek:stream & operator<<(std::eek:stream &os, const foo::Foo::Vec & v)
{
return foo::eek:perator<<(os , v);
}

int main()
{
foo::Foo f;
std::cout << f << std::endl;

foo::Foo::Vec a(4, 1);
std::cout << a << std::endl;
}

--
Patrick Guio
Para//ab, Bergen Centre for Computational Science
Thormøhlensgt. 55, N-5008 Bergen, Norway
Tel : +47 55584361 - Fax: +47 55584295
Mail: echo (e-mail address removed) | perl -pe 'y/a-z/n-za-m/'
URL : http://www.bccs.uib.no
 
P

Patrick Guio

Yes ... please refer to my previous post.

Hi Bob,

I tried to put the insertion operator (declarartion and definitions) in
the global namespace as you mentionned

std::eek:stream & operator<<(std::eek:stream &o, const foo::Foo & v);
std::eek:stream & operator<<(std::eek:stream &o, const foo::Foo::Vec & v);

but then the insertion operator for foo::Foo is not a friend function of
the class Foo any longer. and the compiler complains about privacy-

But if I put both insertions inside

namespace foo
{
class Foo
{
public:
typedef std::vector<unsigned char> Vec;
// insertion operator for foo::Foo call insertion operator for foo::Foo::Vec
friend std::eek:stream & operator<<(std::eek:stream &o, const Foo & f);
friend std::eek:stream & operator<<(std::eek:stream &o, const Vec & v);
private:
Vec a;
};
}

Then the compiler stop complaining about privacy but I cannot use the
insertion for an object in the global namespace of type foo::Foo::Vec
because it does not find the correct insertion.

I tried to only move the insertion operator for foo::Foo::Vec in the
global namespace but it didn't help either, the compiler complain that it
does not find the correct insertion for foo::Foo::Vec in the insertion
foo::Foo.

When fixing insertion for foo::Foo::Vec in global namespace, it creates
trouble for insertion for foo::Foo::Vec in the insertion of foo::Foo and
vice-versa.

Any idea?

Sincerely,

Patrick
 
B

Bob Hairgrove

Hi Bob,

I tried to put the insertion operator (declarartion and definitions) in
the global namespace as you mentionned

std::eek:stream & operator<<(std::eek:stream &o, const foo::Foo & v);
std::eek:stream & operator<<(std::eek:stream &o, const foo::Foo::Vec & v);

but then the insertion operator for foo::Foo is not a friend function of
the class Foo any longer. and the compiler complains about privacy-

Try this:

namespace foo {
class Foo {
friend std::eek:stream & ::eek:perator<<(std::eek:stream &o, const Foo & v);
/* ...etc. */
};
} // namespace foo

Note the "::" in front of "operator".
 
P

Patrick Guio

Try this:

namespace foo {
class Foo {
friend std::eek:stream & ::eek:perator<<(std::eek:stream &o, const Foo & v);
/* ...etc. */
};
} // namespace foo

Note the "::" in front of "operator".

Hi Bob,

Then I get an error message that the "global scope has no
"operator<<"" with Intel compiler "icpc -ansi" (v.8.1) and
that "insertion operator should have been declared inside '::' for
declaration and "not in a namespace surrounding '::'" for the definition
with g++ (v.4.0.1).

Sincerely,

Patrick
 
J

Jonathan Mcdougall

Patrick said:
On Wed, 9 Nov 2005, Patrick Guio wrote:

Hi Jonathan,

Please, don't top-post.
Maybe I should formulate my question differently. Do I need both insertion
operators (in global and foo namespace) for type foo::Foo::Vec so that it
can be used for private member object of class Foo and also in global
namespace? Can that be simplified to one insertion operator?

You have several problems here.

1) you cannot do something like

std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo & f)
{
return os << f.a << std::endl;
}

to define an operator in namespace foo. You have to put the definition
inside the namespace:

namespace foo
{
std::eek:stream & operator<<(std::eek:stream &os, const foo::Foo & f)
{
return os << f.a << std::endl;
}
}

and drop the foo:: qualifier

2) an operator for foo::Foo::Vec will not be found if it is in a
namespace because Vec is a typedef for std::vector. That means

foo::Foo::Vec v;
std::cout << v;

will only search the enclosing namespace (global if you are in main(),
for example) and std::. This is because ADL only applies to the real
type of an object.

3) as soon as an operator is defined, and can be found, you don't need
to define more for the same type. Actually, if you do, you'll get an
ambiguity error.

Forget these. Define a public print() member function that does the
job:

void print(std::eek:stream &out) const
{
// output informations to out, manually output the std::vector
}

Here, call f.print().

This operator won't be used outside namespace foo (if you don't dump it
with "using namespace foo") because, as I said, Vec is a typedef.

Drop this one, it is misleading. On first look, it seems like you are
defining an operator for the user defined type Vec, but this is an
operator for a std::vector<unsigned char>. It may cause ambiguity if
this is in a header and I include it. Either output the vector manually
in Foo::print() (as I did), or make this a named function (such as
output_vector()) in namespace foo.

What you want is:

# include <vector>
# include <iostream>

namespace foo
{
class Foo
{
public:
typedef std::vector<unsigned char> Vec;

void print(std::eek:stream &out) const
{
out << "This is a Foo";
for (Vec::const_iterator itor = v.begin(); itor!=v.end(); ++itor)
{
out << *itor;
}
}

private:
Vec v;
};

std::eek:stream &operator<<(std::eek:stream &out, const Foo &f)
{
f.print(out);
return out;
}
}

int main()
{
foo::Foo f;
std::cout << f;
}


Jonathan
 
J

Jonathan Mcdougall

Bob said:
Try this:

namespace foo {
class Foo {
friend std::eek:stream & ::eek:perator<<(std::eek:stream &o, const Foo & v);
/* ...etc. */
};
} // namespace foo

Note the "::" in front of "operator".

This cannot work because if you qualify a friend declaration, the class
name must be declared before in that scope.


Jonathan
 
P

Patrick Guio

Please, don't top-post.

Oops sorry, but what does top-post mean?
2) an operator for foo::Foo::Vec will not be found if it is in a
namespace because Vec is a typedef for std::vector. That means

foo::Foo::Vec v;
std::cout << v;

will only search the enclosing namespace (global if you are in main(),
for example) and std::. This is because ADL only applies to the real
type of an object.

It will work though with a "using namespace foo" directive (as you also
mention below in your mail) but that's exactly what I want to avoid.
3) as soon as an operator is defined, and can be found, you don't need
to define more for the same type. Actually, if you do, you'll get an
ambiguity error.

I Understand but is there any default stream insertion operator for
std::vector container? I thought there was not.
Forget these. Define a public print() member function that does the
job:

I Understand, it is a good way to handle "printing" for class inheritance
as well.
void print(std::eek:stream &out) const
{
// output informations to out, manually output the std::vector
}
[snip]

Drop this one, it is misleading. On first look, it seems like you are
defining an operator for the user defined type Vec, but this is an
operator for a std::vector<unsigned char>. It may cause ambiguity if
this is in a header and I include it. Either output the vector manually
in Foo::print() (as I did), or make this a named function (such as
output_vector()) in namespace foo.

But that means writing the same code twice? Once for the private member
of type foo::Foo::Vec and once for any foo::Foo::Vec in global
(or any other) namespace ?
What you want is:

# include <vector>
# include <iostream>

namespace foo
{
class Foo
{
public:
typedef std::vector<unsigned char> Vec;

void print(std::eek:stream &out) const
{
out << "This is a Foo";
for (Vec::const_iterator itor = v.begin(); itor!=v.end(); ++itor)
{
out << *itor;
}
}
private:
Vec v;
};

std::eek:stream &operator<<(std::eek:stream &out, const Foo &f)
{
f.print(out);
return out;
}
}

int main()
{
foo::Foo f;
std::cout << f;

How handle in addition?

foo::Foo::Vec v(5, 1);
std::cout << v;
// or output_vector(v); ?

Isn't there a way to avoid code duplication of
for (Vec::const_iterator itor = v.begin(); itor!=v.end(); ++itor)
{
out << *itor;
}
So that it could be used to output object of type foo::Foo::Vec and
outputting the private member of type foo::Foo::Vec?

If I define a class foo::Foo::Vec that inherits std::vector<unsigned char>
instead of using typedef would that help?
Is using typedef's inside a class a good design?

Sincerely,

Patrick
 
J

Jonathan Mcdougall

Patrick said:
Oops sorry, but what does top-post mean?

http://en.wikipedia.org/wiki/Top-posting

Actually, the problem wasn't top posting, but lack of quoting. Google
groups added a "Show quoted text" at the bottom of your message, but it
was empty, sorry.
It will work though with a "using namespace foo" directive (as you also
mention below in your mail) but that's exactly what I want to avoid.

Yes. The thing is, when I do for example

namespace test
{
typedef std::complex<double> my_complex;

void f()
{
my_complex c;
std::cout << c;
}
}

I expect the compiler to keep searching in namespace std, not in
namespace test. Obviously, the compiler cannot take in account every
namespace in which a typedef was used (you could typedef another
typedef which was in another namespace), so it only works with the
underlying type.
I Understand but is there any default stream insertion operator for
std::vector container? I thought there was not.

There is not. Usually, you won't want to output a vector plainly on the
screen, you want to format it, to integrate it on something. That's why
none was defined: what would it do?
I Understand, it is a good way to handle "printing" for class inheritance
as well.

Yes, print() could be virtual for example.
void print(std::eek:stream &out) const
{
// output informations to out, manually output the std::vector
}
[snip]
std::eek:stream & foo::eek:perator<<(std::eek:stream &os, const foo::Foo & f)
{ Here, call f.print().
}
// insertion operator for object as in the main:
// foo::Foo::Vec a(4, 1);
// std::cout << a << std::endl;
std::eek:stream & operator<<(std::eek:stream &os, const foo::Foo::Vec & v)
{
return foo::eek:perator<<(os , v);
}

Drop this one, it is misleading. On first look, it seems like you are
defining an operator for the user defined type Vec, but this is an
operator for a std::vector<unsigned char>. It may cause ambiguity if
this is in a header and I include it. Either output the vector manually
in Foo::print() (as I did), or make this a named function (such as
output_vector()) in namespace foo.

But that means writing the same code twice? Once for the private member
of type foo::Foo::Vec and once for any foo::Foo::Vec in global
(or any other) namespace ?

If Vec is meant to be used both inside and outside the class, make a
named free function to output it.

// in header
# include <vector>
# include <ostream>

namespace foo
{
class Foo
{
public:
typedef std::vector<int> Vec;

void print(std::eek:stream &out) const;

private:
Vec v_;
};

void output_vector(std::eek:stream &out, const Foo::Vec &v);
std::eek:stream &operator<<(std::eek:stream &out, const Foo &f);

} // namespace foo


// in impl file
# include "header"

namespace foo
{

void Foo::print(std::eek:stream &out) const
{
// print Foo related things

output_vector(out, v_);
}

void output_vector(std::eek:stream &out, const Foo::Vec &v)
{
// output v
}

std::eek:stream &operator<<(std::eek:stream &out, const Foo &f)
{
f.print(out);
}

} // namespace foo

Is using typedef's inside a class a good design?

Yes.


Jonathan
 
P

Patrick Guio

On Fri, 11 Nov 2005, Jonathan Mcdougall wrote:

Hi Jonathan,
There is not. Usually, you won't want to output a vector plainly on the
screen, you want to format it, to integrate it on something. That's why
none was defined: what would it do?

Exactly, that was also my understanding.
If Vec is meant to be used both inside and outside the class, make a
named free function to output it.

As an alternative to a free function one could also define a
manipulator struct/class of Foo::Key with a global std::eek:stream insertion
operator like:
// in header
# include <vector>
# include <ostream>

namespace foo
{
class Foo
{
public:
typedef std::vector<int> Vec;

void print(std::eek:stream &out) const;

private:
Vec v_;
};

// void output_vector(std::eek:stream &out, const Foo::Vec &v);

struct output_vector
{
output_vector(const Foo::Vec & v);
Foo::Vec _v;
};

std::eek:stream &operator<<(std::eek:stream &out, const Foo::Vec &v);
std::eek:stream &operator<<(std::eek:stream &out, const Foo &f);

} // namespace foo


// in impl file
# include "header"

namespace foo
{

void Foo::print(std::eek:stream &out) const
{
// print Foo related things

//output_vector(out, v_);

out << output_vector(v_);
}

// void output_vector(std::eek:stream &out, const Foo::Vec &v)
// {
// output v
// }

output_vector::eek:utput_vector(const Foo::Vec & v) :: _v(v) {}

std::eek:stream &operator<<(std::eek:stream &oot, const Foo::Vec &v)
{
// output v
}
std::eek:stream &operator<<(std::eek:stream &out, const Foo &f)
{
// f.print(out);
}

} // namespace foo

That way it is still possible to have a Foo::Vec in chained insertion.

Any idea if this a good design?

Good to know!

Cheers,

Patrick
 
J

Jonathan Mcdougall

Patrick said:
As an alternative to a free function one could also define a
manipulator struct/class of Foo::Key with a global std::eek:stream insertion
operator like:

struct output_vector
{
output_vector(const Foo::Vec & v);
Foo::Vec _v;

You want a reference here. And don't start names with an underscore, it
is reserved for the implemententation. If you want to denote
membership, some people prefix the names with m_ or suffix it with _
and some people like having an unadorned name.
};

std::eek:stream &operator<<(std::eek:stream &out, const Foo::Vec &v);

void Foo::print(std::eek:stream &out) const
{
out << output_vector(v_);
}

output_vector::eek:utput_vector(const Foo::Vec & v) :: _v(v) {}

std::eek:stream &operator<<(std::eek:stream &oot, const Foo::Vec &v)
{
// output v
}

But now you will need an operator<< which takes a const output_vector&.
The Foo::Vec version is unused.
That way it is still possible to have a Foo::Vec in chained insertion.
Any idea if this a good design?

What's good depends on the situation. If you think you can handle it,
it simplifies the code and is easy to maintain, go for it.


Jonathan
 
P

Patrick Guio

On Fri, 11 Nov 2005, Jonathan Mcdougall wrote:

Hi Jonathan,
You want a reference here. And don't start names with an underscore, it
is reserved for the implemententation. If you want to denote
membership, some people prefix the names with m_ or suffix it with _
and some people like having an unadorned name.

Good to know.

std::eek:stream &operator<<(std::eek:stream &out, const output_vector & v);
But now you will need an operator<< which takes a const output_vector&.
The Foo::Vec version is unused.

Oops, typo... But that's what I meant
What's good depends on the situation. If you think you can handle it,
it simplifies the code and is easy to maintain, go for it.

Thank you for this discussion, it was very helpful!
I have now made output_vector a template structure
(output_vector<vector_type>) and defined corresponding template insertion
operators and it works like a charm.

I extend my question to input insertion operator. Is this input method
a good design? Following is the sketch

Cheers,
Patrick

// declaration file
namespace foo
{

template <typename vector_type>
struct input_vector
{
input_vector() {}
vector_type m_vector;
};

template<typename vector_type>
std::istringstream & operator>>(std::istringstream & is, input_vector<vector_type> &v);
// following arespecialisation definitions
std::istringstream & operator>>(std::istringstream & is, input_vector<Foo::Vec> &k);
....
}

// definition file
namespace foo
{
std::istringstream & operator>>(std::istringstream & is, input_vector<Foo::Vec> &k)
{
// input from memory
}
}

Then I can insert

int main()
{
std::istringstream is("1,2,3,4,5");
foo::input_vector<foo::Foo::Vec> iv;
is >> iv;
foo::Foo::Vec V(iv.m_vector);
}
 
J

Jonathan Mcdougall

Patrick said:
I extend my question to input insertion operator. Is this input method
a good design? Following is the sketch

// declaration file
namespace foo
{
template <typename vector_type>
struct input_vector
{
input_vector() {}
vector_type m_vector;
};

template<typename vector_type>
std::istringstream & operator>>(std::istringstream & is, input_vector<vector_type> &v);

// following arespecialisation definitions
std::istringstream & operator>>(std::istringstream & is, input_vector<Foo::Vec> &k);
....
}

// definition file
namespace foo
{
std::istringstream & operator>>(std::istringstream & is, input_vector<Foo::Vec> &k)
{
// input from memory
}
}

Then I can insert

int main()
{
std::istringstream is("1,2,3,4,5");
foo::input_vector<foo::Foo::Vec> iv;
is >> iv;
foo::Foo::Vec V(iv.m_vector);
}

Just want to make sure I understand: is input_vector a wrapper around
standard container classes to define input for them? If yes, I think
you are trying to make things a bit too much generic here.

Will input_vector be used in different contexts? If yes, are you sure
(or does it make sense) that the input will always have the same
format? Wouldn't it be better if you let the class itself interpret the
input?

If not, if you are searching for a more generic way to handle input and
store it in a collection, I think you should go for named functions, or
a class if you need a state. Something like

namespace parser
{
template <class Cont>
istream &comma_separated(std::istream &i, Cont &c);

template <class Cont>
istream &space_separated(std::istream &i, Cont &c);

template <class Cont>
istream &line_separated(std::istream &i, Cont &c);
}

class Test1
{
public:
void f(std::istream &i)
{
// Test1 expects space separated values
parser::space_separated(i, v_);
}

private:
std::vector<int> v_;
};

class Test2
{
public:
void f(std::istream &i)
{
// Test2 expects values on different lines
parser::line_separated(i, v_);
}

private:
std::vector<int> v_;
};

You could specialize parser functions a bit more, but still keeping
them low-level, and use them as building blocks in each class.

Still, these are wild guesses because you haven't said a word on your
"design".


Jonathan
 
P

Patrick Guio

On Mon, 14 Nov 2005, Jonathan Mcdougall wrote:

Hi Jonathan,

Just want to make sure I understand: is input_vector a wrapper around
standard container classes to define input for them? If yes, I think
you are trying to make things a bit too much generic here.

Basically yes it is a wrapper around standard container std::vector with
different "native" types (unsigned char, unsigned short and unsigned
Will input_vector be used in different contexts? If yes, are you sure
(or does it make sense) that the input will always have the same
format? Wouldn't it be better if you let the class itself interpret the
input?

Yes it might be used in different contexts in the sense that the input
may have different formats. As you wrote below, there might be
different separator.
I want to be able to input/import/set keys of different type to be used
in the encryption engine class for testing/benchmarking.

If not, if you are searching for a more generic way to handle input and
store it in a collection, I think you should go for named functions, or
a class if you need a state. Something like

I am not sure to understand What do you mean by a state?
namespace parser
{
template <class Cont>
istream &comma_separated(std::istream &i, Cont &c);

template <class Cont>
istream &space_separated(std::istream &i, Cont &c);

template <class Cont>
istream &line_separated(std::istream &i, Cont &c);
}

Wouldn't it make sense to define a structure
template<typename vec_type>
struct input_vec
{
// default is no separator
input_vec(const std::string sep=std::string()) : sep_(sep) {}
vec_type vec_;
std::string sep_;
};

and then have a single stream insertion operator for struct input_vec that
would use the member input_vec::sep_ ?

template <typename vec:type>
std::istream & operator>>(std::istream & is, input_vec<vec_type> & v);

istream cin;
input_vec<Vec> in(",");
cin >> in;
Vec v(in.vec_);

Or perhaps better use a single class for input_vec and output_vec with
different constructors?

Also if I want to have both insertion operator for std::istream and
std::istringstream, do I need to actually have 2 sets of
definition/declaration for each of them?

Sincerely,

Patrick
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top