您可以为此使用is_detected。我们正在尝试检查给定的类型是否可以使用operator<< 的std::couts 重载之一进行打印,或者该类型本身是否提供了operator<< 用于打印到std::cout。有关我如何实现此功能的更一般说明,请查看 https://www.fluentcpp.com/2017/06/02/write-template-metaprogramming-expressively/
首先,我们为 std::cout 本身的重载定义一个合适的is_detected:
// check std::cout.operator<<(T {})
template<typename = void, typename Arg = void> struct test_operator_of_cout : std::false_type {};
template<typename Arg>
struct test_operator_of_cout<std::void_t<decltype(std::cout.operator<<(std::declval<Arg>()))>, Arg>
: std::true_type {};
template<typename Arg>
constexpr bool test_operator_of_cout_v = test_operator_of_cout<void, Arg>::value;
还有一个用于operator<<(ostream&, T {}) 的所有重载。我在上面发布的链接对此进行了概括,以减少代码冗余。
// check operator<<(std::cout, T {})
template<typename = void, typename Arg = void> struct test_operator_of_struct : std::false_type {};
template<typename Arg>
struct test_operator_of_struct<std::void_t<decltype(operator<<(std::cout, std::declval<Arg>()))>, Arg>
: std::true_type {};
template<typename Arg>
constexpr bool test_operator_of_struct_v = test_operator_of_struct<void, Arg>::value;
我们现在可以使用这些类型特征通过 enable_if 来实现打印功能:
template<typename T> struct MyClass {
T t;
template<
typename Consider = T,
typename = std::enable_if_t<
( test_operator_of_cout_v<Consider> || test_operator_of_struct_v<Consider>)
&& !std::is_arithmetic_v<Consider>
>
> void print() {
std::cout << t;
}
};
这里有两点需要注意:
现在我们可以看看什么是可打印的,什么是不可打印的:
struct NotPrintable {};
struct Printable {
friend std::ostream& operator<<(std::ostream& os, const Printable& p) {
return os;
}
};
auto foo() {
MyClass<const char *> chars;
chars.print(); //compiles
MyClass<std::string> strings;
strings.print(); //compiles
MyClass<std::string_view> string_views;
string_views.print(); //compiles
MyClass<Printable> printables;
printables.print(); // compiles
// MyClass<int> ints;
// ints.print(); // Does not compile due to !is_arithmetiv_v
// MyClass<NotPrintable> not_printable;
// not_printable.print(); //Does not compile due to operator checking
}
您可以在此处查看完整示例:https://godbolt.org/z/ZC9__e