在编译时强制执行正确的状态转换

时间:2015-08-14 04:17:59

标签: c++ templates c++11

我正在处理一些代码,这些代码从某些传入数据创建特定格式的数据包,其中还包括一个时间戳(应该是生成数据的第一个数据位的时间)。在(简化)高级别,这看起来像:

template <typename T>
class packetizer
{
public:
    set_payload(const T* data, uint16_t length, uint32_t timestamp);
};

还需要能够零散地添加数据;类似的东西:

uint16_t initial_data(const T* data, uint16_t length, uint32_t timestamp);
uint16_t append_data(const T* data, uint16_t length);

此处,时间戳应仅在initial_data调用中添加一次。这一切都有效,并且可以在运行时进行检查,但到目前为止,我一直在努力提供尽可能编译时安全的API - 我希望在编译时强制执行上述不变量。我想到这样做的一种方法是返回一个代理:

struct proxy_packetizer
{
private:
    packetizer<T>& packet_ref;

public:
    uint16_t append_data(const T* data, uint16_t length)
    {
        // forward call to packet_ref
    }
};

template <typename T>
class packetizer
{
public:
    proxy_packetizer initial_data(const T* data, uint16_t length, uint32_t timestamp);
};

使用它看起来像:

packetizer p;
auto p2 = p.initial_data(data, length, timestamp);
p2.append_data(....);
auto pkt = p2.create_packet(...);

然而,这有点笨拙,而且仍然容易出错。如果我能以某种方式拥有看起来更像的API,我更喜欢:

packetizer p;
p.initial_data(data, length, timestamp);
p.append_data(...);
auto pkt = p.create_packet();

在编译时强制执行:

  1. initial_data被调用一次,每个数据包只调用一次。
  2. 只有在调用append_data后才能调用
  3. initial_data
  4. create_packet重置此内容(因此必须再次调用initial_data)。
  5. 是否有任何编译时方式来强制执行这些类型的状态转换?

2 个答案:

答案 0 :(得分:1)

我同意@TonyD关于采用RAII方法的评论。我们的想法是将packetizer::packetizer(...)转换为构造函数timestamp。这就是template <typename T> class packetizer { public: packetizer(const T* data, uint16_t length, uint32_t timestamp); uint16_t append_data(const T* data, uint16_t length); }; 只会设置一次的方式:

operator new

由于初始数据可能在运行时间的任何时间出现,因此您可以使用std::unique_ptr<packetizer<T>> packetizer = new Packetizer<T>(data, length, timestamp); ... packetizer->append_data(data, length);

set_payload()

从问题中提到的任何内容来看,我都不能对//Array of videos var MyVideos=["E6RGMRamAFk","IHQr0HCIN2w","CogIXrea6A4"]; var tag = document.createElement('script'); tag.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); var player; function onYouTubeIframeAPIReady() { player = new YT.Player('player', { events: { 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange } }); } function onPlayerReady(event) { //Player is ready, cue the array of videos into the playlist. player.cuePlaylist(MyVideos); } function onPlayerStateChange(event) { } 说些什么;但如果它容易出错,那么我们应该通过改变设计来更好地消除它。

答案 1 :(得分:0)

在Rust中运行IMAP State Machine的实现后,在编译时验证,看起来我正在寻找的是Substructural Type System的标题,在这种情况下,可能是仿射型系统。

我没有尝试过实现它,但可能只使用move-only类型。