我正在试验并尝试制作一个基于模板策略的元库。示例案例是为设备驱动程序聚合 2 个类。类实现device_logic
and connection_logic
,它们不需要依赖于彼此的类型:
- 设备逻辑仅取决于通信协议(消息)。
- connection_logic 只是字节数组的来源,可能使用不同类型的连接:SerialPort、tcp、udp、自定义 PCI Express 设备等。
目标不是在它们上强制使用任何接口或类型。它们必须完全依赖于 API 规范,并且只提供必要的特征。
STL 方法是在标头中定义特征,然后在类中使用它们。所以特征标签必须定义在模板库的头文件中。
// 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");
};
在这种情况下aggregate_device
,聚合连接和设备逻辑。如果设备逻辑可读,则连接逻辑必须提供输入。如果设备逻辑是可写的,则连接必须提供输出。
// device_logic.h
#include <device_traits>
class device_logic
{
public:
using io_type = traits::readableWriteable;
// ... methdos, etc
};
此版本有效,但引入了对模板库的依赖。引入依赖项(甚至是仅包含头文件的库)对开发人员来说并不方便,而且通常对库也不利。有人可能想device_logic
在另一个模块或项目中使用类,但不想拉取它所依赖的模板库。
消除依赖关系的另一个解决方案不是强制类提供者将io_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_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>(), "");
现在我使用第二种方法并且它有效。问题是:
- 这是一种合法的方法吗?
- 对于类提供者来说,这不会令人困惑吗?
- 会(在多大程度上)更难维护?
- 编译性能可能有什么不同?