c++ - 如何检查是否可以从给定类型构造模板类型
问题描述
std::enable_if_t
如果模板参数是任何类型的std::string
(显示如何使用来自多个库的通用字符串执行此操作的答案的奖励积分),我正在尝试使用它来启用一个类。
我不想做“if Text
is a const char*
, std::string
, std::string_view
, etc.” 本质上,我不想具体提及每一个可能的类似字符串的对象。我要对这个对象做的就是将它打印到控制台,并且该Text
对象将被存储为一个类属性。
有没有比考虑每种类型更优雅的方法呢?
解决方案
您可以为此使用is_detected。我们正在尝试检查给定类型是否可以使用std::cout
s 的重载之一进行打印,operator<<
或者该类型本身是否提供operator<<
用于打印到std::cout
. 有关我如何实现此功能的更一般说明,请查看https://www.fluentcpp.com/2017/06/02/write-template-metaprogramming-expressively/
首先,我们is_detected
为 std::cout 本身的重载定义一个合适的:
// 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;
}
};
这里有两点需要注意:
- 您需要
Consider = T
. 否则,编译器将尝试实例化函数的声明,这对于不满足条件的类型来说是错误的。查看此 SO-Answer 以获得更深入的解释:std::enable_if 有条件地编译成员函数 - 由于
!std::is_arithmetic
. 我个人不会包括这个,因为我看不出我的班级不应该允许完全可打印的类型可打印的原因。
现在我们可以看看什么是可打印的,什么是不可打印的:
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
推荐阅读
- android - Android Studio 不显示 res 目录
- javascript - 如何在不使用 vue/javascript 中的 event.target 的情况下显示上传的 zip 文件的名称?
- python - gensim LDA 输出
- css - Laravel 叶片和顺风没有正确混合,我不明白为什么
- arduino - 当 MAX30100 库的 pox.update() 在 Arduino 循环中时,我无法连接
- python - 无法在 Python 中将类对象传递给星图?
- selenium - SSH Selenium 会话在注销时崩溃(即使使用“screen”、“nohup”等)
- frontend - 我需要在 nextJs 中使用 react-bootstrap,但是当需要使用 checkValidaty() 进行验证时,nextJS 返回错误
- php - 如何在aws弹性豆茎上放置ssl
- arrays - 循环通过数组并以角度显示数据