C++如何在编译期判断指定类型是否定义了operator<<重载?
C++ 模板类按类型是否支持
operator<<切换行为实现方案 我们可以通过编译期表达式检测实现需求,以下分别给出C20最简实现和兼容C11及以上版本的实现:
C++20 实现(最简方案)
直接用requires子句对两个重载做互斥约束即可:
#include <iostream> struct HasStreamOp { int i, j; friend std::ostream & operator<<( std::ostream & o, const HasStreamOp & hso ) { o << "HasStreamOp{" << hso.i << ", " << hso.j << "}"; return o; } }; struct HasNoStreamOp { int i, j; }; template<typename T> struct MyClass { T t; // T支持<<时启用该版本 friend std::ostream & operator<<( std::ostream & o, const MyClass & mc ) requires requires(std::ostream& os, const T& val) { { os << val } -> std::same_as<std::ostream&>; } { o << "MyClass{" << mc.t << "}"; return o; } // T不支持<<时启用该版本 friend std::ostream & operator<<( std::ostream & o, const MyClass & mc ) requires (!requires(std::ostream& os, const T& val) { { os << val } -> std::same_as<std::ostream&>; }) { o << "MyClass{opaque T}"; return o; } }; int main() { std::cout << MyClass<HasStreamOp>{.t=HasStreamOp{.i=1,.j=2}} << std::endl; std::cout << MyClass<HasNoStreamOp>{.t=HasNoStreamOp{.i=3,.j=4}} << std::endl; return 0; }
运行输出完全符合预期:
MyClass{HasStreamOp{1, 2}} MyClass{opaque T}
C11/C14/C++17 兼容实现
如果需要兼容旧标准,可以通过SFINAE机制自定义类型特征做检测:
#include <iostream> #include <type_traits> // 自定义检测特征:判断T是否支持std::ostream << 操作 template<typename T, typename = void> struct has_ostream_op : std::false_type {}; template<typename T> struct has_ostream_op<T, decltype(std::declval<std::ostream&>() << std::declval<const T&>(), void())> : std::true_type {}; struct HasStreamOp { int i, j; friend std::ostream & operator<<( std::ostream & o, const HasStreamOp & hso ) { o << "HasStreamOp{" << hso.i << ", " << hso.j << "}"; return o; } }; struct HasNoStreamOp { int i, j; }; template<typename T> struct MyClass { T t; // 借助std::enable_if根据检测结果启用对应重载 template<typename U = T, typename std::enable_if<has_ostream_op<U>::value, int>::type = 0> friend std::ostream & operator<<( std::ostream & o, const MyClass & mc ) { o << "MyClass{" << mc.t << "}"; return o; } template<typename U = T, typename std::enable_if<!has_ostream_op<U>::value, int>::type = 0> friend std::ostream & operator<<( std::ostream & o, const MyClass & mc ) { o << "MyClass{opaque T}"; return o; } }; int main() { std::cout << MyClass<HasStreamOp>{.t=HasStreamOp{.i=1,.j=2}} << std::endl; std::cout << MyClass<HasNoStreamOp>{.t=HasNoStreamOp{.i=3,.j=4}} << std::endl; return 0; }
该版本运行输出和C++20版本完全一致。
内容的提问来源于stack exchange,提问作者Ted Middleton
相关产品推荐
相关产品推荐

