mirror of
https://github.com/boostorg/utility.git
synced 2025-05-09 02:44:10 +00:00
Added bool_testable by Sam Partington
[SVN r18413]
This commit is contained in:
parent
1be04eeec5
commit
88f4e47550
@ -9,6 +9,7 @@
|
||||
// See http://www.boost.org/libs/utility/operators.htm for documentation.
|
||||
|
||||
// Revision History
|
||||
// 04 May 05 Added operator class bool_testable. (Sam Partington)
|
||||
// 21 Oct 02 Modified implementation of operators to allow compilers with a
|
||||
// correct named return value optimization (NRVO) to produce optimal
|
||||
// code. (Daniel Frey)
|
||||
@ -308,6 +309,18 @@ struct indexable : B
|
||||
}
|
||||
};
|
||||
|
||||
// bool_testable -----------------------------------------------------------//
|
||||
// (contributed by Sam Partington, David Abrahams and Daniel Frey) ---------//
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct bool_testable : B
|
||||
{
|
||||
friend bool operator!(const T& t) { return !static_cast<bool>(t); }
|
||||
private:
|
||||
typedef signed char private_number_type;
|
||||
operator private_number_type() const;
|
||||
};
|
||||
|
||||
// More operator classes (contributed by Daryle Walker) --------------------//
|
||||
// (NRVO-friendly implementation contributed by Daniel Frey) ---------------//
|
||||
|
||||
|
145
operators.htm
145
operators.htm
@ -72,6 +72,8 @@
|
||||
<li><a href="#ordering">Ordering Note</a></li>
|
||||
|
||||
<li><a href="#symmetry">Symmetry Note</a></li>
|
||||
|
||||
<li><a href="#safe_bool_note">Safe-Bool Note</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@ -340,6 +342,8 @@ class MyInt
|
||||
|
||||
<li><code><a href="#indexable">indexable<></a></code></li>
|
||||
|
||||
<li><code><a href="#bool_testable">bool_testable<></a></code></li>
|
||||
|
||||
<li>Any composite operator template that includes at least one of the
|
||||
above</li>
|
||||
</ul>
|
||||
@ -527,6 +531,17 @@ const point<float> pi_over_4_normalized = pi_over_4 / length(pi_over_4);
|
||||
Return convertible to <code>bool</code>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a name="bool_testable">bool_testable<T></a></code></
|
||||
td>
|
||||
|
||||
<td><code>bool operator!(const T&)</code></td>
|
||||
|
||||
<td><code>static_cast<bool>(t)</code>.<br>
|
||||
<code>T</code> convertible to <code>bool</code>. See the <a href=
|
||||
"#safe_bool_note">Safe-Bool Note</a>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code><a name="addable1">addable<T></a></code><br>
|
||||
<code>addable1<T></code></td>
|
||||
@ -974,7 +989,132 @@ T operator+( T lhs, const T& rhs )
|
||||
that don't implement the NRVO. <br>
|
||||
<br>
|
||||
|
||||
<h4><a name="safe_bool_note">Safe-Bool</a> Note</h4>
|
||||
|
||||
<p><code><a href="#bool_testable">bool_testable</a></code> provides the
|
||||
antithesis of operator bool, such that the expression <code>if (!p)</code>
|
||||
is valid, whilst also making <code>operator bool</code> safer by preventing
|
||||
accidental conversions to integer types. If <code>operator bool</code>
|
||||
were declared for a class without using
|
||||
<code><a href="#bool_testable">bool_testable</code></a> then expressions
|
||||
such as :</p>
|
||||
|
||||
<pre>
|
||||
void f(int);
|
||||
|
||||
void g(object o)
|
||||
{
|
||||
f(o);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>would compile silently, not warning the user of the (probably)
|
||||
unintended behaviour of passing <code>0</code> or <code>1</code> to
|
||||
<code>f()</code>.</p> <code>bool_testable<></code> prevents these
|
||||
accidental conversions by declaring a private conversion operator to
|
||||
<code>signed char</code>, and not defining the body.</p>
|
||||
|
||||
<h5>Example :</h5>
|
||||
|
||||
<pre>
|
||||
class Stream : boost::bool_testable<Stream>
|
||||
{
|
||||
public:
|
||||
explicit Stream(const char * source);
|
||||
operator bool() const;
|
||||
// non-member bool operator!(const T&) const auto-generated and
|
||||
// operator bool made safe by bool_testable<>
|
||||
|
||||
bool can_print();
|
||||
};
|
||||
|
||||
void g(int);
|
||||
|
||||
void f()
|
||||
{
|
||||
if (Stream s1("source.txt"))
|
||||
{
|
||||
// use s1 ...
|
||||
}
|
||||
|
||||
// or..
|
||||
|
||||
Stream s2("source.txt");
|
||||
if (!s2)
|
||||
{
|
||||
// handle problem
|
||||
}
|
||||
|
||||
// or ..
|
||||
|
||||
if (s2 && s2.can_print()) //* see <a href="#bool_testable_msvc">note</a>
|
||||
{
|
||||
// print something...
|
||||
}
|
||||
|
||||
g(stream); // Will not compile, but would compile
|
||||
// fine without bool_testable<>
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h5><a name="bool_testable_msvc">Note for MSVC version 6 users</a> :</h5>
|
||||
|
||||
<p>Due to a bug in MSVC6, whilst compiling the above code, the compiler
|
||||
will incorrectly diagnose an '<code>ambiguous operator &&</code>' at
|
||||
the asterisked line. The workaround for this is to either:</p>
|
||||
<pre>
|
||||
if (s2)
|
||||
if (s2.can_print())
|
||||
</pre>
|
||||
<p>or</p>
|
||||
<pre>
|
||||
if (!!s2 && s2.can_print())
|
||||
</pre>
|
||||
<p>This problem also affects the other logical operators.</p>
|
||||
|
||||
<h5>Rationale for Implementation</h5>
|
||||
|
||||
<p>Another possible implementation for <code>bool_testable</code> was the
|
||||
safe-bool idiom as found in <a href=
|
||||
"../smart_ptr/shared_ptr.htm#conversions"><code>shared_ptr<></code>
|
||||
</a> written by <a href="../../people/peter_dimov.htm">Peter Dimov</a>.
|
||||
This implementation required the user to provide <code>operator!</code>,
|
||||
and provided a conversion operator to a pointer to member function. This
|
||||
method had the advantage of more descriptive diagnostic messages on most
|
||||
platforms, when the bool conversion was used incorrectly. Unfortunately
|
||||
that implementation had issues when used with a class with other user
|
||||
defined integer conversion operators. This is because the integer
|
||||
conversion operator provided a better match than the conversion to pointer
|
||||
to member function. For example:</p>
|
||||
|
||||
<pre>
|
||||
class MyInt : alternative_bool_testable<MyInt>
|
||||
{
|
||||
public:
|
||||
bool operator!() const;
|
||||
operator int() const;
|
||||
|
||||
// alternative_bool_testable<MyInt> provides :
|
||||
//
|
||||
// typedef void (MyInt::*member_fn)();
|
||||
// operator member_fn() { return &MyInt::f; }
|
||||
|
||||
};
|
||||
|
||||
void g(int);
|
||||
|
||||
void f(const MyInt& i)
|
||||
{
|
||||
if (!i) // fine: calls operator!
|
||||
...
|
||||
|
||||
g(i); // fine: calls operator int
|
||||
|
||||
if (i) // error: calls operator int NOT operator member_fn()
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h3><a name="grpd_oprs">Grouped Arithmetic Operators</a></h3>
|
||||
|
||||
<p>The following templates provide common groups of related operations.
|
||||
@ -2062,6 +2202,11 @@ public:
|
||||
|
||||
<dd>Contributed the NRVO-friendly and symmetric implementation of
|
||||
arithmetic operators.</dd>
|
||||
|
||||
<dt>Sam Partington</dt>
|
||||
|
||||
<dd>Contributed the bool_testable class.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<h2>Note for Users of <a name="old_lib_note">Older Versions</a></h2>
|
||||
|
@ -50,6 +50,7 @@ namespace
|
||||
class Wrapped1
|
||||
: boost::operators<Wrapped1<T> >
|
||||
, boost::shiftable<Wrapped1<T> >
|
||||
, boost::bool_testable<Wrapped1<T> >
|
||||
{
|
||||
public:
|
||||
explicit Wrapped1( T v = T() ) : _value(v) {}
|
||||
@ -80,6 +81,7 @@ namespace
|
||||
{ _value >>= x._value; return *this; }
|
||||
Wrapped1& operator++() { ++_value; return *this; }
|
||||
Wrapped1& operator--() { --_value; return *this; }
|
||||
operator bool() const { return _value != 0; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
@ -555,6 +557,12 @@ template Wrapped6<unsigned int, unsigned char>;
|
||||
|
||||
#define PRIVATE_EXPR_TEST(e, t) BOOST_TEST( ((e), (t)) )
|
||||
|
||||
#define PRIVATE_BOOLEAN_EXPR_TEST(t, res) BOOST_TEST(static_cast<bool>((t)) == (res))
|
||||
#if defined(BOOST_MSVC)
|
||||
#define PRIVATE_MSVC_BOOL_TEST_WORKAROUND(x) (!!x)
|
||||
#else
|
||||
#define PRIVATE_MSVC_BOOL_TEST_WORKAROUND(x) (x)
|
||||
#endif
|
||||
|
||||
int
|
||||
test_main( int , char * [] )
|
||||
@ -631,7 +639,19 @@ test_main( int , char * [] )
|
||||
|
||||
PRIVATE_EXPR_TEST( (i = i1 << i2), (i.value() == 4) );
|
||||
PRIVATE_EXPR_TEST( (i = i2 >> i1), (i.value() == 1) );
|
||||
|
||||
|
||||
PRIVATE_BOOLEAN_EXPR_TEST( i, false);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST( i1, true);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST( i2, true);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST(!i, true);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST(!i1, false);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST(!i2, false);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST(PRIVATE_MSVC_BOOL_TEST_WORKAROUND(i) && PRIVATE_MSVC_BOOL_TEST_WORKAROUND(i2), false);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST(PRIVATE_MSVC_BOOL_TEST_WORKAROUND(i) || PRIVATE_MSVC_BOOL_TEST_WORKAROUND(i2), true);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST(PRIVATE_MSVC_BOOL_TEST_WORKAROUND(i1) && PRIVATE_MSVC_BOOL_TEST_WORKAROUND(i2), false);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST(!i && PRIVATE_MSVC_BOOL_TEST_WORKAROUND(i2), false);
|
||||
PRIVATE_BOOLEAN_EXPR_TEST(PRIVATE_MSVC_BOOL_TEST_WORKAROUND(i1) && !i, false);
|
||||
|
||||
cout << "Performed tests on MyInt objects.\n";
|
||||
|
||||
MyLong j1(1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user