PROTON-1238: [C++ binding] Add fallback operator<< for wrapped proton-c objects
diff --git a/proton-c/bindings/cpp/include/proton/internal/object.hpp b/proton-c/bindings/cpp/include/proton/internal/object.hpp
index 330ebbe..78a990c 100644
--- a/proton-c/bindings/cpp/include/proton/internal/object.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/object.hpp
@@ -27,6 +27,7 @@
 #include "./comparable.hpp"
 
 #include <memory>
+#include <string>
 
 namespace proton {
 
@@ -38,6 +39,7 @@
   protected:
     PN_CPP_EXTERN static void incref(void* p);
     PN_CPP_EXTERN static void decref(void* p);
+    PN_CPP_EXTERN static std::string inspect(void* p);
 };
 
 template <class T> class pn_ptr : private pn_ptr_base, private comparable<pn_ptr<T> > {
@@ -63,6 +65,8 @@
     explicit operator bool() const { return !!ptr_; }
 #endif
 
+    std::string inspect() const { return pn_ptr_base::inspect(ptr_); }
+
     static pn_ptr take_ownership(T* p) { return pn_ptr<T>(p, true); }
 
   private:
@@ -96,6 +100,7 @@
 
     friend bool operator==(const object& a, const object& b) { return a.object_ == b.object_; }
     friend bool operator<(const object& a, const object& b) { return a.object_ < b.object_; }
+    friend std::ostream& operator<<(std::ostream& o, const object& a) { o << a.object_.inspect(); return o; }
   template <class U> friend class proton::thread_safe;
 };
 
diff --git a/proton-c/bindings/cpp/src/object.cpp b/proton-c/bindings/cpp/src/object.cpp
index f881c637..2f3a348 100644
--- a/proton-c/bindings/cpp/src/object.cpp
+++ b/proton-c/bindings/cpp/src/object.cpp
@@ -31,4 +31,10 @@
     if (p) ::pn_decref(const_cast<void*>(p));
 }
 
+std::string pn_ptr_base::inspect(void* p) {
+    if (!p) return std::string();
+    ::pn_string_t* s = ::pn_string(NULL);
+    (void) ::pn_inspect(p, s);
+    return std::string(pn_string_get(s));
+}
 }}