如何删除C++概念

2022-05-17 00:00:00 c++ c++20 c++-concepts

我正在尝试实现一个小型网络库来学习概念,并且我正在尝试找到一种方法来定义简洁的概念,而不必在依赖的概念上携带模板参数。例如,我有以下概念:

template <typename ValueT>
concept bool Value = true;

template <typename BufferT>
concept bool Buffer = requires(BufferT buf)
{
    { buf.Size() } -> std::size_t;
    { buf.Capacity() } -> std::size_t;
    { buf.Put(Value</* How can I resolve this to any value */>) } -> bool;
    { buf.Take(Value</* How can I resolve this to any value */>) } -> bool;
};

template <typename ReadableT>
concept bool Readable = requires(ReadableT r)
{
    { r.Read(Buffer</* How can I resolve this to any buffer */>) } -> void;
};

template <typename WritableT>
concept bool Writable = requires(WritableT w)
{
    { w.Write(Buffer</* How can I resolve this to any buffer */>) } -> void;
};

template <typename ChannelT>
concept bool Channel = requires(ChannelT chan)
{
    requires Readable<ChannelT>;
    requires Writable<ChannelT>;
};
如何在不显式拥有模板参数的情况下定义ValueBuffer概念?这有可能吗?我会直觉地这样写:

template <typename ReadableT>
concept bool Readable = requires(ReadableT r)
{
    template <typename ValueT> 
    { r.Read(Buffer<ValueT>) } -> void;
};

但这不能编译(显然),并且我找不出正确的语法。

编辑:我觉得正确的语法是这样的:

template <typename BufferT>
concept bool Buffer = requires(BufferT buf, Value val)
{
    { buf.Size() } -> std::size_t;
    { buf.Capacity() } -> std::size_t;
    { buf.Put(val) } -> bool;
    { buf.Take(val) } -> bool;
};

但GCC(8.3.0)打印此消息:

internal compiler error: in synthesize_implicit_template_parm, at cp/parser.c:39141
    concept bool Buffer = requires(BufferT buf, Value val)
                                             ^~~~~
Please submit a full bug report, with preprocessed source if appropriate.

解决方案

我的想法是我应该能够将任何结构、整数、字符串或任何东西真正放入缓冲区

这不是一个概念能够回答的问题。它也不是故意的。

概念用于约束模板。在某种程度上,模板应该知道它在做什么。特定的模板实例化不适用于"任何结构、整数或字符串";它适用于特定类型,这些类型由其模板参数和依赖于它们的表达式定义。概念也是如此。

请考虑如下模板:

template<typename Buff, typename Iterator>
void InsertIntoBuffer(Buff &buf, Iterator beg, Iterator ed)
{
  for(; beg != ed; ++beg)
    buf.Put(*beg);
}

此函数要对Buff施加的约束是NOT"具有可以接受任何对象的Put函数。"实际约束是"有一个Put函数,它可以接受Iteratoroperator*返回的内容。"

因此,"放置"和"获取"不仅仅是对Buff的约束;它还需要知道正在"放置"或"获取"的内容。

换句话说,受约束的不是类型,而是操作作为一个整体受到约束。

所以你会对Buffer有一个基本约束,这是一个有大小和容量的东西。但您还应该有一个PutBuffer约束,该约束要求Buffer可以Put给定类型。

同样,Readable实际上是ReadableFromBuffer,其中提供了缓冲区类型。

相关文章