【发布时间】:2021-12-05 20:24:28
【问题描述】:
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为参数,返回convertible以引用self。
然后我们删除operator<< 重载(阻止隐式函数生成和显式重载),这些重载在<< 的左侧具有满足HasLogMethodReturningReferenceToSelf 的类型和在<< 的右侧的类型不是std::string的类型:
template<HasLogMethodReturningReferenceToSelf T, class U>
requires(!std::convertible_to<U, std::string>) auto operator<<(T, U) = delete;
- 我不明白什么时候会删除重载?在某些特定类型
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
- 为什么?
【问题讨论】:
-
你有这个答案有效的例子吗?因为除非我弄错了,
HasOutputStreamOperatorOverloadsForBasicTypes要求基本类型工作确实会破坏它:gcc.godbolt.org/z/z4esEc1vx -
@Frank 您添加的示例确实有效,因为您的
Logger1缺少重载,这就是我们想要捕获的。见:gcc.godbolt.org/z/6G8x9rG8G -
哦,我明白了。有问题的类型列表是如此随意,以至于我认为您想要“隐式转换为 std::string + 没有其他隐式转换 + 一些基于每个记录器定义的任意类型列表”。我没有意识到
doubleshortlong long等...在您的设计中是从不可记录类型。
标签: c++ require c++20 c++-concepts