混合使用DELETE关键字和概念和约束

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

In my question我收到了适合我的答复,但我不知道它是如何工作的。

尤其是,我不明白delete关键字和概念是如何删除operator<<的重载的。

(我将从accepted answer中逐段粘贴代码的重构版本。)

enum class LogLevel
{
    info,
    warning,
    error
};

template<typename T>
concept HasLogMethodReturningReferenceToSelf = requires(T v)
{
    {
        v.log(LogLevel{})
        } -> std::convertible_to<T&>;
};

所以,我们在这里定义了一个概念,它检查一个类型是否有方法log(),该方法接受LogLevel作为参数,并返回可转换为对自身的引用。

然后,我们删除重载的operator<<重载(块隐式函数生成和显式重载),这些重载的<<左侧的类型满足HasLogMethodReturningReferenceToSelf,而<<右侧的类型不是std::string

template<HasLogMethodReturningReferenceToSelf T, class U>
requires(!std::convertible_to<U, std::string>) auto operator<<(T, U) = delete;
  1. 我不明白什么时候会删除重载?在实例化某个特定类型的概念期间(&Q;)T?因为,不是每种类型都满足条件(这会破坏代码库?)?

因为后面定义了另一个概念,它检查基本类型的输出流运算符重载:

template<typename T>
concept HasOutputStreamOperatorOverloadsForBasicTypes =
    requires(T v, unsigned unsigned_, int int_, float float_, unsigned char unsigned_char_, char char_)
{
    {
        v << "string literal" //
          << unsigned_        //
          << int_             //
          << float_           //
          << unsigned_char_   //
          << char_            //
        } -> std::convertible_to<T&>;
};

最后,我们定义了Loggable概念:

template<typename T>
concept Loggable = HasLogMethodReturningReferenceToSelf<T> && HasOutputStreamOperatorOverloadsForBasicTypes<T>;

通常,我会定义一个很大的Loggable概念:

template<typename T>
concept Loggable = requires(T v)
{
    {
        v.log(LogLevel{})
        } -> std::convertible_to<T&>;
    {
        v << "string literal" //
          << unsigned_        //
          << int_             //
          << float_           //
          << unsigned_char_   //
          << char_            //
        } -> std::convertible_to<T&>;
};

,然后以某种方式限制隐式转换。我猜答案的作者必须将这两个requires表达式一分为二,否则,当我使用后一个Loggable定义,然后使用定义后的delete重载:

template<Loggable T, class U>
requires(!std::convertible_to<U, std::string>) auto operator<<(T, U) = delete;

我收到编译错误:

致命错误:递归模板实例化超过了1024的最大深度

  1. 为什么?

解决方案

我不明白什么时候会删除重载?在.期间 为某些特定类型T实例化概念(&Q)?因为,不是 对于满足条件的每种类型(它将打破 CodeBase?)?

当我们在Requires子句中检查v << unsigned_是否格式良好时,如果您的Logger类没有operator<<unsigned重载,则会选择之前定义的全局operator<<,因为U将直接实例化为unsigned,并且没有隐式转换,因此它具有更高的优先级。

并且由于删除了全局operator<<,因此v << unsigned_的格式不正确,未满足约束。

相关文章