我为“implies”运算符创建了一个宏。它通常运行良好,但在概念或要求子句中使用时,Clang 会中断。
namespace detail
{
template <typename T>
concept BoolLike = requires(T &&t) {(T &&)t ? true : false;};
struct Implies
{
template <BoolLike T>
friend constexpr bool operator||(T &&lhs, Implies)
{
return !bool((T &&)lhs);
}
};
}
#define IMPLIES ||::detail::Implies{}||
template <typename T>
concept A = true IMPLIES true;
static_assert(A<int>);
Clang 说:
<source>:19:18: error: atomic constraint must be of type 'bool' (found '::detail::Implies')
19 | concept A = true IMPLIES true;
| ^~~~~~~
<source>:16:19: note: expanded from macro 'IMPLIES'
16 | #define IMPLIES ||::detail::Implies{}||
| ^~~~~~~~~~~~~~~~~~~
虽然 GCC 和 MSVC 很乐意接受此代码。哪个编译器是正确的?
重载逻辑运算符实际上在约束表达式中不起作用(在顶层):约束规范化机制分别根据其句法形式将形式
E1 || E2
和的表达式转换为析取和连词,而不考虑是否有用户提供的运算符重载( [temp.constr.normal])。E1 && E2
A
在这个特定的例子中,这意味着的约束表达式的范式包含由表达式 形成的原子约束::detail::Implies{}
,而该表达式永远不会是 类型bool
。[温度.构造.原子]/3:
由于该程序从不检查无效的原子约束是否满足(因为
||
短路),因此它是错误格式的,不需要进行诊断([temp.res.general]/6.4):