Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I correctly assign cout to a static ostream reference variable?

I'm defining a class like this:

class StaticRuntimeContext {
 public:
  enum Verbosity {
    kHIGH,
    kMEDIUM,
    kLOW,
    kSILENT
  };
  static void Construct();
  static std::ostream& stdout1() {return stdout1_;}
  static std::ostream& stdout2() {return stdout2_;}
  static std::ostream& stdout3() {return stdout3_;}
  static std::ostream& stderr() {return stderr_;}
 protected:
 private:
  static std::ostream& stdout1_;
  static std::ostream& stdout2_;
  static std::ostream& stdout3_;
  static std::ostream& stderr_;
};

I'm defining the construct function as:

void StaticRuntimeContext::Construct() {
  std::ostream& test = cout;
  stdout1_ = cout;
  stdout2_ = cout;
  //stdout3_ = NULL;
  stderr_ = cerr;
}

I cannot understand why assigning cout to test (std::ostream&) is OK to compile but the compiler produces error messages for the rest like "stdout1_=cout". The error message is:

/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/ios_base.h:791:5: error: ‘std::ios_base& std::ios_base::operator=(const std::ios_base&)’ is private

I'm wondering what I should do to correctly assign cout to these ostream reference variables. Thanks!

like image 586
derekhh Avatar asked Nov 09 '11 19:11

derekhh


2 Answers

It's because references have value semantics, and the operator = is copying the object instead of assigning a new reference.

Instead of references you should define static pointers, assign them in Construct, and return references in your accessors

  static std::ostream& stdout1() {return *stdout1_;}
  static std::ostream& stdout2() {return *stdout2_;}
  static std::ostream& stdout3() {return *stdout3_;}
  static std::ostream& stderr()  {return *stderr_;}
 protected:
 private:
  static std::ostream* stdout1_;
  static std::ostream* stdout2_;
  static std::ostream* stdout3_;
  static std::ostream* stderr_;

void StaticRuntimeContext::Construct() {
  stdout1_ = &cout;
  stdout2_ = &cout;
  stdout3_ = &cout;
  stderr_ = &cerr;
}

EDIT: And you must add this in your .cpp file

std::ostream* StaticRuntimeContext::stdout1_ = NULL;
std::ostream* StaticRuntimeContext::stdout2_ = NULL;
std::ostream* StaticRuntimeContext::stdout3_ = NULL;
std::ostream* StaticRuntimeContext::stderr_ = NULL;
like image 82
Gabriel Cuvillier Avatar answered Nov 17 '22 04:11

Gabriel Cuvillier


This code

std::ostream& test = cout;

is not an assignment, but a construction of a new reference. It can also be written

std::ostream& test(cout);

without the equal sign. The effect is the same.

A reference cannot be rebound once it is created, so it must be set to its value when created. The static members also have to be defined somewhere, like in the corresponding .cpp file. Just set the values there:

 std::ostream& StaticRuntimeContext::stdout1_ = std::cout;
 std::ostream& StaticRuntimeContext::stdout2_ = std::cout;
 std::ostream& StaticRuntimeContext::stdout3_ = std::clog;
 std::ostream& StaticRuntimeContext::stderr_  = std::cerr;
like image 2
Bo Persson Avatar answered Nov 17 '22 04:11

Bo Persson