inheriting from ostream to customize standard output

A

aaragon

Hi everybody,

I was wondering if there is an easy way that one could create a custom
class that inherits from std::eek:stream to override the functionality of
operator<<.

Since I work with several processes, I want to avoid some of them to
print information to standard output (or enable that to print
information concurrently).

I tried the following but it didn't work:

class Output_strem : public std::eek:stream {

typedef std::eek:stream base_type;

public:

Output_strem() : base_type() {}


template <typename T>
std::eek:stream& operator<<(T t) {

#ifdef MPI

std::eek:stream& os = *this;
os<<"["<<Parallel_base::rank_<<"] ";

#endif

return *this;
}
};

As you see, nothing is telling the ostream object to print to standard
output. I saw the definition of the cout in the standard library and
it looks like this:


ios_base::Init::Init()
{
if (__gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 1) == 0)
{
// Standard streams default to synced with "C" operations.
_S_synced_with_stdio = true;

new (&buf_cout_sync) stdio_sync_filebuf<char>(stdout);
// other created objects

// The standard streams are constructed once only and never
// destroyed.
new (&cout) ostream(&buf_cout_sync);
// other created objects

// NB: Have to set refcount above one, so that standard
// streams are not re-initialized with uses of ios_base::Init
// besides <iostream> static object, ie just using <ios> with
// ios_base::Init objects.
__gnu_cxx::__atomic_add_dispatch(&_S_refcount, 1);
}
}


Can someone point me in the right direction?

Thank you all,

aa
 
L

Larry Evans

Hi everybody,

I was wondering if there is an easy way that one could create a custom
class that inherits from std::eek:stream to override the functionality of
operator<<.

Since I work with several processes, I want to avoid some of them to
print information to standard output (or enable that to print
information concurrently).

Boost iostreams enables you to install a filter in a streambuf:

http://www.boost.org/doc/libs/1_46_1/libs/iostreams/doc/index.html

Maybe you could install a filtering streambuf in cout to do what you
want; however, since I've never done any kind of filtering such as
you describe, I can't provide any concrete suggestions on how to do
that.

-regards,
Larry
 
A

aaragon

Boost iostreams enables you to install a filter in a streambuf:

 http://www.boost.org/doc/libs/1_46_1/libs/iostreams/doc/index.html

Maybe you could install a filtering streambuf in cout to do what you
want; however, since I've never done any kind of filtering such as
you describe, I can't provide any concrete suggestions on how to do
that.

-regards,
 Larry

Thanks Larry for your reply. I ended up doing the following:

class Output_stream : public std::eek:stream {

typedef std::eek:stream base_type;

size_t id_;

public:


Output_stream(const std::eek:stream& os = cout, size_t id =
size_t(-1)) : base_type(os.rdbuf()), id_(id) {}

template <typename T>
std::eek:stream& operator<<(typename
Type_traits<T>::parameterType t) {

#ifdef MPI

std::eek:stream& os = *this;

if (id_ != size_t(-1))
if (Parallel_base::rank_ != id_)
return *this;

os<<"["<<Parallel_base::rank_<<"] ";

#endif

return base_type::eek:perator<<(t);
}

};

It seems to work fine, only that it doesn't work because of the
template function is not being called. I need to figure out why.

Alejandro
 
L

Larry Evans

Boost iostreams enables you to install a filter in a streambuf:

http://www.boost.org/doc/libs/1_46_1/libs/iostreams/doc/index.html

Maybe you could install a filtering streambuf in cout to do what you
want; however, since I've never done any kind of filtering such as
you describe, I can't provide any concrete suggestions on how to do
that.

-regards,
Larry

Thanks Larry for your reply. I ended up doing the following:

class Output_stream : public std::eek:stream {

typedef std::eek:stream base_type;

size_t id_;

public:


Output_stream(const std::eek:stream& os = cout, size_t id =
size_t(-1)) : base_type(os.rdbuf()), id_(id) {}

template <typename T>
std::eek:stream& operator<<(typename
Type_traits<T>::parameterType t) {

#ifdef MPI

std::eek:stream& os = *this;

if (id_ != size_t(-1))
if (Parallel_base::rank_ != id_)
return *this;

os<<"["<<Parallel_base::rank_<<"] ";

#endif

return base_type::eek:perator<<(t);
}

};

It seems to work fine, only that it doesn't work because of the
template function is not being called. I need to figure out why.

Alejandro

Hi Alejandro,

I think the problem is something cused by "nondeduced context"
(I may not be getting the term exactly right, but it's something
like that.) The problem is the compiler cannot decide which type,
T, to use when instantiating operator<<. To illustrate the problem,
a simplified version of your code attached.

The problem occurs when the #if on line 43 is:

#if 1

which causes the:

operator<<(T::U const&)

code to be used. Now, if there are a T1 and T2 both with the
same value for U, then how can the compiler know which T to
choose? For example, in the attached code, buth C<1> and C<2>
have the same value for their U, which is B. Now, I know what
you're probably thinking, "Well it's obvious from
the call site, which C<I> to use. I had the exact same question:

http://groups.google.com/group/comp...ondeduced+context+workaround#2cb76b2c61eb37ae

See if reading that thread can clear things up. I still have trouble
with really understanding since it seems to obvious from looking
at the code:

a<<C<1>::B()

that C<1> should be the T in the operator<< template. Hmmm..
wait, but then what about:

a<<B()

which C<I> should be used then, Oh, but then, in this case
there base::eek:perator<< would be used. I guess the compiler
would have to have too much context information that the
writers decided just to disallow this.

Confused? You're not alone?

HTH.

-Larry
 
J

James Kanze

I was wondering if there is an easy way that one could create
a custom class that inherits from std::eek:stream to override the
functionality of operator<<.

No, thank goodness. The behavior of the operator<< is part of
the contract of ostream, and too much other code counts on it.
What you can do is define your own streaming class; when
appropriate, it could delegate to an ostream.
Since I work with several processes, I want to avoid some of them to
print information to standard output (or enable that to print
information concurrently).
I tried the following but it didn't work:
class Output_strem : public std::eek:stream {
typedef std::eek:stream base_type;
public:
Output_strem() : base_type() {}
template <typename T>
std::eek:stream& operator<<(T t) {
#ifdef MPI
std::eek:stream& os = *this;
os<<"["<<Parallel_base::rank_<<"] ";
#endif
return *this;
}
};
Can someone point me in the right direction?

Use delegation instead of inheritance.
 

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

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top