Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 零依赖特性定义_C++_Generics_Template Meta Programming_Typetraits_Policy Based Design - Fatal编程技术网

C++ 零依赖特性定义

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标记必须在模板库的头中定

我正在试验并尝试制作一个基于模板策略的元库。示例案例是为设备驱动程序聚合2个类。 这些类实现了
设备逻辑
连接逻辑
,它们不需要依赖于彼此的类型:

  • 设备逻辑仅取决于通信协议(消息)
  • 连接逻辑只是字节数组的一个来源,可以使用不同类型的连接:SerialPort、tcp、udp、自定义PCI express设备等
我们的目标不是强迫他们使用任何接口或类型。它们必须完全依赖于API规范,并且只提供必要的特性

STL方法是在标题中定义特征,然后在类中使用它们。 因此,traits标记必须在模板库的头中定义

// 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关于方法/属性的存在

这些类型可能是:

  • 类内(至于
    是透明的
  • 或者作为外部特征提供,例如
    std::iterator_traits
    (如果可能,它甚至允许从类中提取内部typedef)
请注意,只有外部特征可能以非侵入性方式支持内置类型(指针,
int
,…)或外部类型(第三个库或特征的标准库)

是否(在多大程度上)更难维持

两者之间有一种交易

  • “物理”依赖关系,即东西之间的联系更紧密,可能更容易保持同步,但要创建依赖关系

  • 没有“物理”依赖关系,因此很难保持同步

编译的性能有什么不同

和往常一样,你必须测量

比如说

要一起使用,似乎必须包含类似的代码,但不必按相同的顺序,所以我打赌会有类似的性能

单独使用时,应避免额外使用一个
#include
(因此,如果使用pch

这是合法的方法吗?
对于一个类提供者来说,这不是很混乱吗

标准使用不同的方法:

  • 类型的存在,例如应该有“type”
    的透明比较器是透明的(正如
    使用is\u transparent=void;

  • 具体标签如下

  • 甚至只需鸭子式键入(不检查模板)

  • 或SFINAE关于方法/属性的存在

这些类型可能是:

  • 类内(至于
    是透明的
  • 或者作为外部特征提供,例如
    std::iterator_traits
    (如果可能,它甚至允许从类中提取内部typedef)
请注意,只有外部特征可能以非侵入性方式支持内置类型(指针,
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>(), "");