理论上,从 C + + 11开始,所有的运算符都可以只允许一个“次要”附加语言功能的短路行为(当 lambdas 被引入时,在1979年“ C with class”开始后32年,在 c + + 98之后仍然是可观的16) :
C + + 只需要一种方法来将参数注释为惰性求值-一个隐藏的 lambda-以避免求值,直到必要和允许(前提条件满足)。
理论上的特性是什么样子的(记住,任何新特性都应该是可以广泛使用的) ?
应用于函数参数的注释 lazy使函数成为期望函数的模板,并使编译器将表达式打包到函数中:
A operator&&(B b, __lazy C c) {return c;}
// And be called like
exp_b && exp_c;
// or
operator&&(exp_b, exp_c);
它看起来就像:
template<class Func> A operator&&(B b, Func& f) {auto&& c = f(); return c;}
// With `f` restricted to no-argument functors returning a `C`.
// And the call:
operator&&(exp_b, [&]{return exp_c;});
I & rsquo; m 不完全确定下面所有代码的标准一致性(仍然有点流感) ,但是它使用 Visual C + + 12.0(2013)和 MinGW g + + 4.8编译得很干净:
#include <iostream>
using namespace std;
void say( char const* s ) { cout << s; }
struct S
{
using Op_result = S;
bool value;
auto is_true() const -> bool { say( "!! " ); return value; }
friend
auto operator&&( S const a, S const b )
-> S
{ say( "&& " ); return a.value? b : a; }
friend
auto operator||( S const a, S const b )
-> S
{ say( "|| " ); return a.value? a : b; }
friend
auto operator<<( ostream& stream, S const o )
-> ostream&
{ return stream << o.value; }
};
template< class T >
auto is_true( T const& x ) -> bool { return !!x; }
template<>
auto is_true( S const& x ) -> bool { return x.is_true(); }
#define SHORTED_AND( a, b ) \
[&]() \
{ \
auto&& and_arg = (a); \
return (is_true( and_arg )? and_arg && (b) : and_arg); \
}()
#define SHORTED_OR( a, b ) \
[&]() \
{ \
auto&& or_arg = (a); \
return (is_true( or_arg )? or_arg : or_arg || (b)); \
}()
auto main()
-> int
{
cout << boolalpha;
for( int a = 0; a <= 1; ++a )
{
for( int b = 0; b <= 1; ++b )
{
for( int c = 0; c <= 1; ++c )
{
S oa{!!a}, ob{!!b}, oc{!!c};
cout << a << b << c << " -> ";
auto x = SHORTED_OR( SHORTED_AND( oa, ob ), oc );
cout << x << endl;
}
}
}
}
X operator&&(Y const& y, Z const& z)
{
if (shortcircuitCondition(y))
return shortcircuitEvaluation(y);
<"Syntax for an evaluation-Point for z here">
return actualImplementation(y,z);
}
很少有人希望超载 operator||和 operator&&,因为很少有情况下,在非布尔上下文中编写 a && b实际上是直观的。我所知道的唯一例外是表达式模板,例如用于嵌入式 DSL。而且只有少数病例能从短路评估中获益。表达式模板通常不需要,因为它们用于形成稍后计算的表达式树,所以总是需要表达式的两边。
因此,通过使 &&直接超载为非法,问题得到了解决。相反,在 C # 中必须重载 二运算符,每个运算符都回答这两个问题中的一个。
class C
{
// Is this thing "false-ish"? If yes, we can skip computing the right
// hand size of an &&
public static bool operator false (C c) { whatever }
// If we didn't skip the RHS, how do we combine them?
public static C operator & (C left, C right) { whatever }
...
(旁白: 实际上,是三个。C # 要求如果提供了操作符 false,那么还必须提供操作符 true,这就回答了这个问题: 这个东西是“真实的吗?”.通常没有理由只提供一个这样的操作符,因此 C # 需要两个操作符。)
考虑下面这种形式的陈述:
C cresult = cleft && cright;
编译器为此生成代码,就像您编写的伪 C # 一样:
C cresult;
C tempLeft = cleft;
cresult = C.false(tempLeft) ? tempLeft : C.&(tempLeft, cright);