C++ 零依赖特性定义
我正在试验并尝试制作一个基于模板策略的元库。示例案例是为设备驱动程序聚合2个类。 这些类实现了C++ 零依赖特性定义,c++,generics,template-meta-programming,typetraits,policy-based-design,C++,Generics,Template Meta Programming,Typetraits,Policy Based Design,我正在试验并尝试制作一个基于模板策略的元库。示例案例是为设备驱动程序聚合2个类。 这些类实现了设备逻辑和连接逻辑,它们不需要依赖于彼此的类型: 设备逻辑仅取决于通信协议(消息) 连接逻辑只是字节数组的一个来源,可以使用不同类型的连接:SerialPort、tcp、udp、自定义PCI express设备等 我们的目标不是强迫他们使用任何接口或类型。它们必须完全依赖于API规范,并且只提供必要的特性 STL方法是在标题中定义特征,然后在类中使用它们。 因此,traits标记必须在模板库的头中定
设备逻辑
和连接逻辑
,它们不需要依赖于彼此的类型:
- 设备逻辑仅取决于通信协议(消息)
- 连接逻辑只是字节数组的一个来源,可以使用不同类型的连接:SerialPort、tcp、udp、自定义PCI express设备等
// device_traits.h
namespace traits
{
// tags to be defined as io_type
struct writeable;
struct readable;
struct wretableReadable;
template <typename T>
constexpr bool is_writeable()
{
return std::is_same_v<writeable, typename T::io_type>() ||
std::is_same_v<wretableReadable, typename T::io_type>();
}
// functions for readable and readableWriteable
}
template <typename ConnectionLogic,
typename DeviceLogic>
class aggregate_device
{
static_assert(!traits::readable<DeviceLogic>() ||
(traits::readable<DeviceLogic>() &&
traits::readable<ConnectionLogic>()),
"Device logic is readable so must be ConnectionLogic");
static_assert(!traits::writeable<DeviceLogic>() ||
(traits::writeable<DeviceLogic>() &&
traits::writeable<ConnectionLogic>()),
"Device logic is writeable so must be ConnectionLogic");
};
此版本可以工作,但引入了对模板库的依赖。引入依赖项(即使是只包含标题的库)对开发人员来说并不方便,通常对库也不好。有人可能想在另一个模块或项目中使用device\u logic
类,但不想提取它所依赖的模板库
消除依赖关系的另一个解决方案不是强制类提供者将io\u type
标记注入到类中,而是自己定义它们
// device_traits.h
namespace traits
{
template<typename, typename = void>
struct is_writeable : std::false_type{};
// here we just check if a typename has a type writeable
template<typename T>
struct is_writeable<T, std::void_t<typename T::writeable>> : std::true_type{};
// functions for readable and readableWriteable
// aggregator class
}
//device\u traits.h
名称空间特性
{
模板
结构是可写的:std::false\u类型{};
//这里我们只是检查一个typename是否有一个可写的类型
模板
结构是可写的:std::true\u类型{};
//用于可读和可读写的函数
//聚合器类
}
//设备逻辑.h
//不要什么都不包括
类设备逻辑
{
公众:
//定义类型
结构可写;
};
/////
#包括
静态断言(traits::is_writeable(),“”);
现在,我使用第二种方法,它是有效的。
问题是:
- 这是合法的方法吗
- 对于一个类提供者来说,这不是很混乱吗
- 是否(在多大程度上)更难维持
- 编译的性能有什么不同
对于一个类提供者来说,这不是很混乱吗 标准使用不同的方法:
- 类型的存在,例如应该有“type”
的透明比较器是透明的(正如
)使用is\u transparent=void;
- 具体标签如下
- 甚至只需鸭子式键入(不检查模板)
- 或SFINAE关于方法/属性的存在
- 类内(至于
)是透明的
- 或者作为外部特征提供,例如
(如果可能,它甚至允许从类中提取内部typedef)std::iterator_traits
int
,…)或外部类型(第三个库或特征的标准库)
是否(在多大程度上)更难维持
两者之间有一种交易
- “物理”依赖关系,即东西之间的联系更紧密,可能更容易保持同步,但要创建依赖关系
- 没有“物理”依赖关系,因此很难保持同步
#include
(因此,如果使用pch
这是合法的方法吗?对于一个类提供者来说,这不是很混乱吗 标准使用不同的方法:
- 类型的存在,例如应该有“type”
的透明比较器是透明的(正如
)使用is\u transparent=void;
- 具体标签如下
- 甚至只需鸭子式键入(不检查模板)
- 或SFINAE关于方法/属性的存在
- 类内(至于
)是透明的
- 或者作为外部特征提供,例如
(如果可能,它甚至允许从类中提取内部typedef)std::iterator_traits
int
,…)或外部类型(第三个库或特征的标准库)
是否(在多大程度上)更难维持
两者之间有一种交易
- “物理”依赖关系,即东西之间的联系更紧密,可能更容易保持同步,但要创建依赖关系
- 没有“物理”依赖关系,因此很难保持同步
独立使用时,您应该避免使用一个额外的
#include
(这取决于它的大小/数量,如果使用pch,…)。如何,而不是在静态断言中测试可写的
标记,测试具有预期签名的写函数的实际可用性?(当然,阅读也是如此)@prog fh我在想它。但是如果一个写方法是一个模板,这是不可能的decltype(&T::write)
将失败,因为需要缺少一个实例化。此外,这只是一个例子。以它为例
// device_traits.h
namespace traits
{
template<typename, typename = void>
struct is_writeable : std::false_type{};
// here we just check if a typename has a type writeable
template<typename T>
struct is_writeable<T, std::void_t<typename T::writeable>> : std::true_type{};
// functions for readable and readableWriteable
// aggregator class
}
// device_logic.h
// don't include nothing
class device_logic
{
public:
// define a type
struct writeable;
};
/////
#include <device_traits>
static_assert(traits::is_writeable<device_logic>(), "");