我希望能够写作
if (3 <= X <= 10)
{
}
else if (20 < X < 100)
{ //...etc
在 C++ 中并让它正确评估。我知道你可以在 Python 中做到这一点,我认为这是表达条件的一种非常易读的方式。
我不想写:
if (3 <= X && X <= 10) //etc.
我怎样才能在 C++ 中做到这一点?可能吗?重载运算符会是什么样子?如果不是,你能解释为什么它不可能吗?
我希望能够写作
if (3 <= X <= 10)
{
}
else if (20 < X < 100)
{ //...etc
在 C++ 中并让它正确评估。我知道你可以在 Python 中做到这一点,我认为这是表达条件的一种非常易读的方式。
我不想写:
if (3 <= X && X <= 10) //etc.
我怎样才能在 C++ 中做到这一点?可能吗?重载运算符会是什么样子?如果不是,你能解释为什么它不可能吗?
你确定你需要这个吗?
[更新]
过了一会儿,我想到了一个看起来并不完全疯狂的想法;)
您需要从包装第一个元素开始:
int main() {
int x = 134, y = 14;
if (IntComp(7) <= x <= 134)
{
std::cout << "Hello ";
}
if (IntComp(134) > y > 12)
{
std::cout << "world!";
}
}
这里的魔力:
class IntComp {
public:
IntComp(int x, bool result = true) : value(x), result(result) {}
IntComp operator <= (int x) const
{
return IntComp(x, result && value <= x);
}
IntComp operator > (int x) const
{
return IntComp(x, result && value > x);
}
operator bool() const { return result; }
private:
int value;
bool result;
};
你不能在 C++ 中做到这一点。您必须将其分解为两个单独的操作:
if (3 <= X && X <= 10)
{
...
}
else if (20 < X && X < 100)
{
...
}
就个人而言,我认为所有这些运算符重载解决方案都有些过度设计。两个简单的函数模板怎么样?
template<typename A, typename B, typename C>
bool ordered(const A& a, const B& b, const C& c)
{
return (a <= b) && (b <= c);
}
template<typename A, typename B, typename C>
bool between(const A& a, const B& b, const C& c)
{
return (a < b) && (b < c);
}
void foobar(int X)
{
if (ordered(3, X, 10))
{
}
else if (between(20, X, 100))
{
// ...
}
}
令人惊奇的是,C++ 将允许您使用用户定义的类型来做一些事情......
struct C
{
int value;
bool state;
C( int value, bool state=true ) : value(value), state(state) {}
};
C operator <= ( int a, C b )
{
if ( a <= b.value ) return C(b.value,true);
return C(b.value,false);
}
bool operator <= ( C a, int b )
{
if ( a.state && a.value <= b ) return true;
return false;
}
std::ostream & operator << ( std::ostream & os, C c ) { os<<c.value; return os; }
void test( C X )
{
if (3 <= X <= 10) cerr<<"(3 <= X <= 10) is true for X="<<X<<"\n";
}
int main()
{
test(2), test(3), test(4), test(10), test(11);
}
输出...
$ ./how-to-implement-3-x-10-in-c++.cpp
(3 <= X <= 10) is true for X=3
(3 <= X <= 10) is true for X=4
(3 <= X <= 10) is true for X=10
由于 C++11 具有基于范围的for
循环,最简单和最简单的是Range
类模板,它除了支持循环外,还支持集合成员资格检查,例如作为方法contains
。
一个明显的优势是,这种方法只有一个简单的模板,具有多种用途。
还有一个可能不那么明显的优势是它支持const
循环变量,比如……
int main()
{
using std::wcout; using std::endl; using cpp::range;
for( auto const i : range( 2, 7 ) )
{
wcout << i << " ";
}
wcout << endl;
if( range( 2, 7 ).contains( 3 ) )
{
wcout << "Yes!" << endl;
}
else
{
wcout << "No!" << endl;
}
}
像这样的定义
#include <utility> // std::begin, std::end
namespace cpp {
template< class Derived >
class Comparable
{
public:
friend bool operator<=( Derived const& a, Derived const& b )
{ return !(b < a); }
friend bool operator>=( Derived const& a, Derived const& b )
{ return !(a < b); }
friend bool operator>( Derived const& a, Derived const& b )
{ return (b < a); }
friend bool operator!=( Derived const& a, Derived const& b )
{ return !(a == b); }
};
template< class TpValue >
class Range
{
public:
typedef TpValue Value;
private:
Value first_;
Value last_;
public:
class Iter
: public Comparable< Iter >
{
private:
Value current_;
public:
Value operator*() const { return current_; }
void operator++() { ++current_; }
friend bool operator<( Iter const a, Iter const b )
{ return a.current_ < b.current_; }
friend bool operator==( Iter const a, Iter const b )
{ return a.current_ == b.current_; }
explicit Iter( Value const v )
: current_( v )
{}
};
Value first() const { return first_; }
Value last() const { return last_; }
Iter begin() const { return Iter( first_ ); }
Iter end() const { return Iter( last_ + 1 ); }
bool contains( Value const x ) const
{ return (first_ <= x && x <= last_); }
Range( Value const first, Value const last )
: first_( first ), last_( last )
{}
};
template< class Value >
Range< Value > range( Value const first, Value const last )
{
return Range< Value >( first, last );
}
template< class Value >
typename Range< Value >::Iter begin( Range< Value > const& r )
{ return r.begin(); }
template< class Value >
typename Range< Value >::Iter end( Range< Value > const& r )
{ return r.end(); }
} // namespace cpp
将其概括为处理浮点范围留给读者作为练习(这里不要求)。
唯一的办法就是按照马龙建议的方式。不幸的是,没有办法通过运算符重载来规避这一点。重载运算符将如下所示:operator<=<=
,其中 <=<= 是三元运算符。唯一的三元运算符是“?:”,这会使您的语法看起来非常难看。最好用老式的方式来做。
首先:标准要求运算符重载在参数中至少涉及一个用户定义的类型。因此X
必须是用户定义的类型。
如果是,那么它就成为可能,没有问题。
struct Integral {
Integral(int i): _value(i) {}
int _value;
};
class ComparisonResult {
public:
ComparisonResult(Integral last, bool result): _last(last), _result(result) {}
operator bool() const { return _result; }
Integral last() const { return _last; }
private:
Integral _last;
bool _result;
};
ComparisonResult operator<(Integral left, integral right) {
return ComparisonResult(right, left._value < right._value);
}
ComparisonResult operator<(ComparisonResult cr, Integral right) {
if (not cr) { return ComparisonResult(right, false); }
return ComparisonResult(right, cr.last() < right);
}
// Other operators here, with the same ComparisonResult type
接着:
int main() {
Integral X(4);
if (3 < X < 10) { std::cout << "Hello, World!\n"; }
}