15

Update 2: I'm not sure why this is still being upvoted (March 2014). This appears to be fixed since I asked this question many years ago. Make sure you're using a recent version of boost.

UPDATE: Perhaps C++ streams need to be initialized in order to format numbers, and the initialization is not happening when the shared library is loaded in Python?

I am calling

cout << 1 << "!" << endl; 

in a method that is exported to a shared library via boost.python. It doesn't print anything, but if I do

cout << "%" << "!" << endl; 

it works.

This is important because I want to do this:

ostream& operator <<(ostream &os, const Bernoulli& b) {
    ostringstream oss;
    oss << b.p() * 100.0 << "%";
    return os << oss.str();
}

I exposed that by doing this:

BOOST_PYTHON_MODULE(libdistributions)
{
    class_<Bernoulli>("Bernoulli")
        .def(init<>())
        .def(init<double>())

        .def("p", &Bernoulli::p)
        .def("set_p", &Bernoulli::set_p)
        .def("not_p", &Bernoulli::not_p)

        .def("Entropy", &Bernoulli::Entropy)
        .def("KL", &Bernoulli::KL)
        .def(self_ns::str(self))
    ;
}

but when I call the str method in python on a Bernoulli object, I get nothing. I suspect the simpler cout problem is related.

Neil G
  • 32,138
  • 39
  • 156
  • 257
  • I did not have problem with iostreams and boost.python... maybe the problem comes from a more subtile bug? However, the technique in the docs (http://1dl.us/dAD) didn't work for me, I had to write `.def("__str__", &print_wrapper)`. What is `self_ns`?. Also, in your method, why not just `{return os << b.p() * 100.0 << "%"; }`? – rafak Dec 06 '10 at 19:59
  • @rafak the reason for doing it via ostringstream is explained in this question: http://stackoverflow.com/questions/2249018/using-setw-with-user-defined-ostream-operators – Neil G Dec 06 '10 at 20:31
  • @rafak where is `print_wrapper` defined? I can't find it in boost. – Neil G Dec 06 '10 at 20:35
  • I should have said that it is mine: template inline std::string print_wrapper(const C& obj) { std::ostringstream os; os << obj; return os.str(); } – rafak Dec 06 '10 at 21:03
  • @Neil G: nice trick for doing it via ostringstream! – rafak Dec 06 '10 at 21:06
  • @rafak FYI: print_wrapper has the same as the usual str solution for me. – Neil G Dec 06 '10 at 22:59
  • 1
    Possible duplicate of: http://stackoverflow.com/questions/2828903/build-problems-when-adding-str-method-to-boost-python-c-class/3084341#3084341 – vz0 Jan 25 '11 at 04:17

3 Answers3

3

I also run into this problem a while ago, using self_ns as outlined in the answers here Build problems when adding `__str__` method to Boost Python C++ class

The reason for using self_ns is explained by Dave himself here http://mail.python.org/pipermail/cplusplus-sig/2004-February/006496.html


Just for the sake of debugging, please try

inline std::string toString(const Bernoulli& b) 
{
   std::ostringstream s;
   s << b;
   return s.str(); 
}

And replace .def(self_ns::str(self)) with

class_<Bernoulli>("Bernoulli")
[...]
.def("__str__", &toString)
Community
  • 1
  • 1
H. Brandsmeier
  • 957
  • 5
  • 19
  • I used self_ns as shown in the question, and it didn't fix this problem. – Neil G Nov 12 '12 at 11:05
  • Can you try `.def(self_ns::str(self_ns::self))`? – H. Brandsmeier Nov 12 '12 at 11:37
  • Also you could try to add a `std::cout << "hello world << std::endl" inside your operator<< and report if your function gets called at all. – H. Brandsmeier Nov 12 '12 at 11:38
  • Hi, I did try that code. I'm pretty sure that Boost.Python is not properly initializing the integer-to-string code for streams. Using a printf works, but using ostream doesn't. – Neil G Nov 13 '12 at 00:01
  • @Neil G: Did you try what I wrote under "Just for the sake of debugging", did that work? – H. Brandsmeier Nov 13 '12 at 10:20
  • Thanks for your help Brandsmeier. I retried the self_ns::str method and it worked. I guess it must have been fixed since I posted this question two years ago. – Neil G Nov 13 '12 at 10:41
2

Have you tried using boost::format instead? Since you are already using boost, it shouldn't be too much of a hassle.

boost::format( "%d%%" ) % ( b.p() * 100.0 )

Another thing, try passing std::endl explicitly to the output os.

UncleZeiv
  • 18,272
  • 7
  • 49
  • 77
  • Thanks. The number is still not being shown, but the "%" sign is there. It appears that the buffer in which the number is stringified is not being created. – Neil G Jan 11 '11 at 20:56
  • 1
    Hm. I'll try to reproduce the problem then. – UncleZeiv Jan 12 '11 at 12:39
  • Thank you. Please let me know if you can't reproduce it and if you ever find a solution. – Neil G Jan 19 '11 at 01:50
  • Ok, I wrote an empty `Bernoulli` class, with `p` defined as `double p() {return 2.5;}`; in Python, `str(b)` prints `250%` as expected. I used boost 1.42 and Python 2.5. Which versions are you using? – UncleZeiv Feb 01 '11 at 12:12
  • I'm using boost 1.48 and Python 3.1 now. – Neil G Jan 28 '12 at 22:10
  • I am going to do some more testing with your solution and then maybe start a bounty. It's not a big deal for me anymore, but it seems that many other people are running into this given the upvotes on the question. – Neil G Jan 28 '12 at 23:11
0

have you tried flushing the stream prior to using the .str() method?

oss << b.p() * 100.0 << "%" << std::flush;
Vukasin Toroman
  • 636
  • 7
  • 21