cpp: add template_streamop generation with runtime/compiler test coverage
Add template_streamop support in the C++ generator so generated operator<< and printTo can target generic stream-like output types.
Keep default behavior unchanged when the option is not set (std::ostream signatures remain).
Add compiler/runtime coverage for template generation, friend declaration correctness, enums, and collection printing.
default:
```cpp
std::ostream& operator<<(std::ostream& out, const SimpleStruct& obj);
class SimpleStruct {
public:
void printTo(std::ostream& out) const;
};
```
with `template_streamop`:
```cpp
template <typename OStream_>
OStream_& operator<<(OStream_& out, const SimpleStruct& obj);
class SimpleStruct {
public:
template <typename OStream_>
void printTo(OStream_& out) const;
};
```
diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
index 3d7beab..dcbcf2c 100644
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -143,6 +143,7 @@
src/thrift/TProcessor.h \
src/thrift/TApplicationException.h \
src/thrift/TLogging.h \
+ src/thrift/TPrintTo.h \
src/thrift/TToString.h \
src/thrift/TBase.h \
src/thrift/TConfiguration.h \
diff --git a/lib/cpp/src/thrift/TPrintTo.h b/lib/cpp/src/thrift/TPrintTo.h
new file mode 100644
index 0000000..d3d5cb4
--- /dev/null
+++ b/lib/cpp/src/thrift/TPrintTo.h
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _THRIFT_TPRINTTO_H_
+#define _THRIFT_TPRINTTO_H_ 1
+
+#include <map>
+#include <set>
+#include <vector>
+
+namespace apache {
+namespace thrift {
+
+// Generic printTo template - streams value directly to output
+template <typename OStream, typename T>
+void printTo(OStream& out, const T& t) {
+ out << t;
+}
+
+// Special handling of i8 datatypes (THRIFT-5272) - cast to int to avoid char output
+template <typename OStream>
+void printTo(OStream& out, const int8_t& t) {
+ out << static_cast<int>(t);
+}
+
+// Forward declarations for collection types
+template <typename OStream, typename K, typename V>
+void printTo(OStream& out, const std::map<K, V>& m);
+
+template <typename OStream, typename T>
+void printTo(OStream& out, const std::set<T>& s);
+
+template <typename OStream, typename T>
+void printTo(OStream& out, const std::vector<T>& t);
+
+// Pair support
+template <typename OStream, typename K, typename V>
+void printTo(OStream& out, const std::pair<K, V>& v) {
+ printTo(out, v.first);
+ out << ": ";
+ printTo(out, v.second);
+}
+
+// Iterator range support
+template <typename OStream, typename Iterator>
+void printTo(OStream& out, Iterator beg, Iterator end) {
+ for (Iterator it = beg; it != end; ++it) {
+ if (it != beg)
+ out << ", ";
+ printTo(out, *it);
+ }
+}
+
+// Vector support
+template <typename OStream, typename T>
+void printTo(OStream& out, const std::vector<T>& t) {
+ out << "[";
+ printTo(out, t.begin(), t.end());
+ out << "]";
+}
+
+// Map support
+template <typename OStream, typename K, typename V>
+void printTo(OStream& out, const std::map<K, V>& m) {
+ out << "{";
+ printTo(out, m.begin(), m.end());
+ out << "}";
+}
+
+// Set support
+template <typename OStream, typename T>
+void printTo(OStream& out, const std::set<T>& s) {
+ out << "{";
+ printTo(out, s.begin(), s.end());
+ out << "}";
+}
+
+} // namespace thrift
+} // namespace apache
+
+#endif // _THRIFT_TPRINTTO_H_