expression templates 可能有一种方法可以实现您想要的。下面是如何处理此问题的草图(无法编译,缺少很多细节,请注意讲师)。首先,您设置一个类模板来表示逻辑值并在它们上定义一些运算符。
template<typename T, typename Type = Atomic<T> >
class Logical;
template<typename T, typename E1, typename E2>
Logical<T, OpOr<T, E1, E2> > operator||(Logical<T, E1> lhs, Logical<T, E2> rhs);
template<typename T, typename E1, typename E2>
Logical<T, OpAnd<T, E1, E2> > operator&&(Logical<T, E1> lhs, Logical<T, E2> rhs);
template<typename T, typename E1, typename E2>
Logical<T, OpEq<T, E1, E2> > operator==(Logical<T, E1> lhs, Logical<T, E2> rhs)
{ return OpEq<T, E1, E2>()(lhs, rhs); } // delegate to class template
因为函数模板不能部分特化,所以您将实际工作委托给类模板。
// primary template
template<typename T, typename E1, typename E2> class OpEq;
// specialization for atomic comparisons
template<typename T>
class OpEq<T, Atomic<T>, Atomic<T> >
{
bool operator()(Atomic<T> lhs, Atomic<T> rhs)
{ return lhs == rhs; }
}
// apply distributive rule
template<typename T>
class OpEq<T, Atomic<T>, OpOr<T, Atomic<T>, Atomic<T> > >
{
bool operator()(Atomic<T> lhs, OpOr<T, Atomic<T>, Atomic<T> > rhs)
{ return (lhs == rhs.first()) && (lhs == rhs.second()); }
}
显然,要获得所需的自然 C++ 语法,需要使用大量繁重的模板机制。但是通过大量的努力和阅读,您最终可能会得到一些不错的东西。 (您必须定义 Atomic、OpAnd、OpOr、设置表示包含子表达式的第一个和第二个分支等。)
但是,即使您成功了,您的方案中也会得到真正奇怪的语义。您的提议是要求 == 比 || 或 && 左分配。 IE。解析
X == (Y @OP Z)
作为
(X == Y) @OP (X == Z)
@OP 等于 && 或 ||。我认为要求== 保持对称 是很自然的。这将要求您还对&& 和|| 施加== 的右分布。 IE。解析
(X @OP Y) == Z
作为
(X == Z) @OP (Y == Z)
但是,如果将两者与表达式组合为(A @OP1 B) == (C @OP2 D),则会出现逻辑不一致。例如。结果取决于您应用左分布和右分布的顺序。
从左到右:
(A @OP1 B) == (C @OP2 D)
((A @OP1 B) == C) @OP2 ((A @OP1 B) == D)
((A == C) @OP1 (B ==C)) @OP2 ((A == D) @OP1 (B == D))
从右到左:
(A @OP1 B) == (C @OP2 D)
(A == (C @OP2 D)) @OP1 (B == (C @OP2 D))
((A == C) @OP2 (A == D)) @OP1 ((B == C) @OP2 (B == D))
在这两种情况下,都会比较相同的 4 对元素,但它们在表达式树上传播的方式略有不同。如果@OP1 和@OP2 相同,那么您可以展平整个树并重新排序术语以获得唯一的结果。 ,如果您在== 的两侧使用相同的运算符,则可以,因为&& 和|| 都是关联 以及可交换。
但是对于混合运算符,结果表达式通常会有所不同。
更新:正如 cmets 中提到的这个和其他答案,你也失去了内置类型的某些属性。首先,短路规则,重载运算符不遵守。对于不涉及指针取消引用或其他资源访问的逻辑表达式(if(p && p->value()) 或if(file && file.open()) 等),这不会影响正确性,只会影响效率。否则要小心!其次,还提到常量/表达式的混合评估会出错。这有一个简单(但冗长)的解决方法:只需使用 std::integral_constant(或 boost::mpl::int_)作为包装器。