Merge pull request #55 from tonyelewis/add-constexpr-support

Add constexpr to operators (w/ basic docs, tests)
This commit is contained in:
Daniel Frey 2020-04-12 13:07:24 +02:00 committed by GitHub
commit bdc5b5cf3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 146 additions and 33 deletions

View File

@ -109,6 +109,17 @@
# pragma warning( disable : 4284 ) // complaint about return type of
#endif // operator-> not begin a UDT
// Define BOOST_OPS_CONSTEXPR to be like BOOST_CONSTEXPR but empty under MSVC < v19.22
#ifdef BOOST_MSVC
#if BOOST_MSVC_FULL_VER >= 192200000
#define BOOST_OPS_CONSTEXPR constexpr
#else
#define BOOST_OPS_CONSTEXPR
#endif
#else
#define BOOST_OPS_CONSTEXPR BOOST_CONSTEXPR
#endif
// In this section we supply the xxxx1 and xxxx2 forms of the operator
// templates, which are explicitly targeted at the 1-type-argument and
// 2-type-argument operator forms, respectively.
@ -132,34 +143,34 @@ template <typename T> class empty_base {};
template <class T, class U, class B = operators_detail::empty_base<T> >
struct less_than_comparable2 : B
{
friend bool operator<=(const T& x, const U& y) { return !static_cast<bool>(x > y); }
friend bool operator>=(const T& x, const U& y) { return !static_cast<bool>(x < y); }
friend bool operator>(const U& x, const T& y) { return y < x; }
friend bool operator<(const U& x, const T& y) { return y > x; }
friend bool operator<=(const U& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const U& x, const T& y) { return !static_cast<bool>(y > x); }
friend BOOST_OPS_CONSTEXPR bool operator<=(const T& x, const U& y) { return !static_cast<bool>(x > y); }
friend BOOST_OPS_CONSTEXPR bool operator>=(const T& x, const U& y) { return !static_cast<bool>(x < y); }
friend BOOST_OPS_CONSTEXPR bool operator>(const U& x, const T& y) { return y < x; }
friend BOOST_OPS_CONSTEXPR bool operator<(const U& x, const T& y) { return y > x; }
friend BOOST_OPS_CONSTEXPR bool operator<=(const U& x, const T& y) { return !static_cast<bool>(y < x); }
friend BOOST_OPS_CONSTEXPR bool operator>=(const U& x, const T& y) { return !static_cast<bool>(y > x); }
};
template <class T, class B = operators_detail::empty_base<T> >
struct less_than_comparable1 : B
{
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
friend BOOST_OPS_CONSTEXPR bool operator>(const T& x, const T& y) { return y < x; }
friend BOOST_OPS_CONSTEXPR bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend BOOST_OPS_CONSTEXPR bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};
template <class T, class U, class B = operators_detail::empty_base<T> >
struct equality_comparable2 : B
{
friend bool operator==(const U& y, const T& x) { return x == y; }
friend bool operator!=(const U& y, const T& x) { return !static_cast<bool>(x == y); }
friend bool operator!=(const T& y, const U& x) { return !static_cast<bool>(y == x); }
friend BOOST_OPS_CONSTEXPR bool operator==(const U& y, const T& x) { return x == y; }
friend BOOST_OPS_CONSTEXPR bool operator!=(const U& y, const T& x) { return !static_cast<bool>(x == y); }
friend BOOST_OPS_CONSTEXPR bool operator!=(const T& y, const U& x) { return !static_cast<bool>(y == x); }
};
template <class T, class B = operators_detail::empty_base<T> >
struct equality_comparable1 : B
{
friend bool operator!=(const T& x, const T& y) { return !static_cast<bool>(x == y); }
friend BOOST_OPS_CONSTEXPR bool operator!=(const T& x, const T& y) { return !static_cast<bool>(x == y); }
};
// A macro which produces "name_2left" from "name".
@ -362,7 +373,7 @@ BOOST_BINARY_OPERATOR( right_shiftable, >> )
template <class T, class U, class B = operators_detail::empty_base<T> >
struct equivalent2 : B
{
friend bool operator==(const T& x, const U& y)
friend BOOST_OPS_CONSTEXPR bool operator==(const T& x, const U& y)
{
return !static_cast<bool>(x < y) && !static_cast<bool>(x > y);
}
@ -371,7 +382,7 @@ struct equivalent2 : B
template <class T, class B = operators_detail::empty_base<T> >
struct equivalent1 : B
{
friend bool operator==(const T&x, const T&y)
friend BOOST_OPS_CONSTEXPR bool operator==(const T&x, const T&y)
{
return !static_cast<bool>(x < y) && !static_cast<bool>(y < x);
}
@ -380,28 +391,28 @@ struct equivalent1 : B
template <class T, class U, class B = operators_detail::empty_base<T> >
struct partially_ordered2 : B
{
friend bool operator<=(const T& x, const U& y)
friend BOOST_OPS_CONSTEXPR bool operator<=(const T& x, const U& y)
{ return static_cast<bool>(x < y) || static_cast<bool>(x == y); }
friend bool operator>=(const T& x, const U& y)
friend BOOST_OPS_CONSTEXPR bool operator>=(const T& x, const U& y)
{ return static_cast<bool>(x > y) || static_cast<bool>(x == y); }
friend bool operator>(const U& x, const T& y)
friend BOOST_OPS_CONSTEXPR bool operator>(const U& x, const T& y)
{ return y < x; }
friend bool operator<(const U& x, const T& y)
friend BOOST_OPS_CONSTEXPR bool operator<(const U& x, const T& y)
{ return y > x; }
friend bool operator<=(const U& x, const T& y)
friend BOOST_OPS_CONSTEXPR bool operator<=(const U& x, const T& y)
{ return static_cast<bool>(y > x) || static_cast<bool>(y == x); }
friend bool operator>=(const U& x, const T& y)
friend BOOST_OPS_CONSTEXPR bool operator>=(const U& x, const T& y)
{ return static_cast<bool>(y < x) || static_cast<bool>(y == x); }
};
template <class T, class B = operators_detail::empty_base<T> >
struct partially_ordered1 : B
{
friend bool operator>(const T& x, const T& y)
friend BOOST_OPS_CONSTEXPR bool operator>(const T& x, const T& y)
{ return y < x; }
friend bool operator<=(const T& x, const T& y)
friend BOOST_OPS_CONSTEXPR bool operator<=(const T& x, const T& y)
{ return static_cast<bool>(x < y) || static_cast<bool>(x == y); }
friend bool operator>=(const T& x, const T& y)
friend BOOST_OPS_CONSTEXPR bool operator>=(const T& x, const T& y)
{ return static_cast<bool>(y < x) || static_cast<bool>(x == y); }
};

View File

@ -454,7 +454,7 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
</caption>
<tr>
<td colspan="3">
<td colspan="4">
<table align="center" border="1">
<caption>
<em>Key</em>
@ -482,6 +482,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<th>Supplied Operations</th>
<th>Requirements</th>
<th>Propagates <code>constexpr</code>?</th>
</tr>
<tr>
@ -496,6 +498,9 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>t &lt; t1</code>.<br>
Return convertible to <code>bool</code>. See the <a href=
"#ordering">Ordering Note</a>.</td>
<td>Since <code>C++11</code><br>
<span style="font-size:small;">(except <a href="https://developercommunity.visualstudio.com/content/problem/414193/rejects-valid-constexpr-marked-friend-function-def.html">MSVC &lt; v19.22</a>)</span></td>
</tr>
<tr>
@ -513,6 +518,9 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>t &lt; u</code>. <code>t &gt; u</code>.<br>
Returns convertible to <code>bool</code>. See the <a href=
"#ordering">Ordering Note</a>.</td>
<td>Since <code>C++11</code><br>
<span style="font-size:small;">(except <a href="https://developercommunity.visualstudio.com/content/problem/414193/rejects-valid-constexpr-marked-friend-function-def.html">MSVC &lt; v19.22</a>)</span></td>
</tr>
<tr>
@ -524,6 +532,9 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>t == t1</code>.<br>
Return convertible to <code>bool</code>.</td>
<td>Since <code>C++11</code><br>
<span style="font-size:small;">(except <a href="https://developercommunity.visualstudio.com/content/problem/414193/rejects-valid-constexpr-marked-friend-function-def.html">MSVC &lt; v19.22</a>)</span></td>
</tr>
<tr>
@ -537,6 +548,9 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>t == u</code>.<br>
Return convertible to <code>bool</code>.</td>
<td>Since <code>C++11</code><br>
<span style="font-size:small;">(except <a href="https://developercommunity.visualstudio.com/content/problem/414193/rejects-valid-constexpr-marked-friend-function-def.html">MSVC &lt; v19.22</a>)</span></td>
</tr>
<tr>
@ -548,6 +562,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp += t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -560,6 +576,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp += u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -572,6 +590,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp -= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -584,6 +604,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp -= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -594,6 +616,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(u); temp -= t</code>.<br>
Return convertible to <code>T</code>.</td>
<td>No</td>
</tr>
<tr>
@ -606,6 +630,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp *= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -619,6 +645,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp *= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -630,6 +658,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp /= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -641,6 +671,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp /= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -651,6 +683,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(u); temp /= t</code>.<br>
Return convertible to <code>T</code>.</td>
<td>No</td>
</tr>
<tr>
@ -662,6 +696,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp %= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -673,6 +709,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp %= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -683,6 +721,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(u); temp %= t</code>.<br>
Return convertible to <code>T</code>.</td>
<td>No</td>
</tr>
<tr>
@ -694,6 +734,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp |= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -706,6 +748,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp |= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -717,6 +761,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp &amp;= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -729,6 +775,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp &amp;= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -740,6 +788,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp ^= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -752,6 +802,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp ^= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -762,6 +814,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); ++t</code><br>
Return convertible to <code>T</code>.</td>
<td>No</td>
</tr>
<tr>
@ -772,6 +826,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); --t;</code><br>
Return convertible to <code>T</code>.</td>
<td>No</td>
</tr>
<tr>
@ -784,6 +840,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp &lt;&lt;= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -796,6 +854,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp &lt;&lt;= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -808,6 +868,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp &gt;&gt;= t1</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -820,6 +882,8 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>T temp(t); temp &gt;&gt;= u</code>.<br>
Return convertible to <code>T</code>. See the <a href=
"#symmetry">Symmetry Note</a>.</td>
<td>No</td>
</tr>
<tr>
@ -831,6 +895,9 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>t &lt; t1</code>.<br>
Return convertible to <code>bool</code>. See the <a href=
"#ordering">Ordering Note</a>.</td>
<td>Since <code>C++11</code><br>
<span style="font-size:small;">(except <a href="https://developercommunity.visualstudio.com/content/problem/414193/rejects-valid-constexpr-marked-friend-function-def.html">MSVC &lt; v19.22</a>)</span></td>
</tr>
<tr>
@ -842,6 +909,9 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>t &lt; u</code>. <code>t &gt; u</code>.<br>
Returns convertible to <code>bool</code>. See the <a href=
"#ordering">Ordering Note</a>.</td>
<td>Since <code>C++11</code><br>
<span style="font-size:small;">(except <a href="https://developercommunity.visualstudio.com/content/problem/414193/rejects-valid-constexpr-marked-friend-function-def.html">MSVC &lt; v19.22</a>)</span></td>
</tr>
<tr>
@ -856,6 +926,9 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
<td><code>t &lt; t1</code>. <code>t == t1</code>.<br>
Returns convertible to <code>bool</code>. See the <a href=
"#ordering">Ordering Note</a>.</td>
<td>Since <code>C++11</code><br>
<span style="font-size:small;">(except <a href="https://developercommunity.visualstudio.com/content/problem/414193/rejects-valid-constexpr-marked-friend-function-def.html">MSVC &lt; v19.22</a>)</span></td>
</tr>
<tr>
@ -874,6 +947,9 @@ const point&lt;float&gt; pi_over_4_normalized = pi_over_4 / length(pi_over_4);
u</code>.<br>
Returns convertible to <code>bool</code>. See the <a href=
"#ordering">Ordering Note</a>.</td>
<td>Since <code>C++11</code><br>
<span style="font-size:small;">(except <a href="https://developercommunity.visualstudio.com/content/problem/414193/rejects-valid-constexpr-marked-friend-function-def.html">MSVC &lt; v19.22</a>)</span></td>
</tr>
</table>

View File

@ -50,9 +50,9 @@ namespace
void operator!() const;
public:
convertible_to_bool( const bool value ) : _value( value ) {}
BOOST_OPS_CONSTEXPR convertible_to_bool( const bool value ) : _value( value ) {}
operator unspecified_bool_type() const
BOOST_OPS_CONSTEXPR operator unspecified_bool_type() const
{ return _value ? &convertible_to_bool::_value : 0; }
};
@ -64,12 +64,12 @@ namespace
, boost::shiftable<Wrapped1<T> >
{
public:
explicit Wrapped1( T v = T() ) : _value(v) {}
T value() const { return _value; }
BOOST_OPS_CONSTEXPR explicit Wrapped1( T v = T() ) : _value(v) {}
BOOST_OPS_CONSTEXPR T value() const { return _value; }
convertible_to_bool operator<(const Wrapped1& x) const
BOOST_OPS_CONSTEXPR convertible_to_bool operator<(const Wrapped1& x) const
{ return _value < x._value; }
convertible_to_bool operator==(const Wrapped1& x) const
BOOST_OPS_CONSTEXPR convertible_to_bool operator==(const Wrapped1& x) const
{ return _value == x._value; }
Wrapped1& operator+=(const Wrapped1& x)
@ -932,5 +932,31 @@ main()
cout << "Performed tests on MyLongInt objects.\n";
// Where C++11 constexpr is available, compile-time test some of the operators that are able to use it to propagate constexpr
#ifndef BOOST_NO_CXX11_CONSTEXPR
#if !defined(BOOST_MSVC) || (_MSC_VER >= 1922)
static_assert( ! static_cast<bool>( MyInt{ 1 } == MyInt{ 2 } ), "" );
static_assert( MyInt{ 1 } != MyInt{ 2 }, "" );
static_assert( MyInt{ 1 } < MyInt{ 2 }, "" );
static_assert( MyInt{ 1 } <= MyInt{ 2 }, "" );
static_assert( ! static_cast<bool>( MyInt{ 1 } > MyInt{ 2 } ), "" );
static_assert( ! static_cast<bool>( MyInt{ 1 } >= MyInt{ 2 } ), "" );
static_assert( ! static_cast<bool>( MyInt{ 2 } == MyInt{ 1 } ), "" );
static_assert( MyInt{ 2 } != MyInt{ 1 }, "" );
static_assert( ! static_cast<bool>( MyInt{ 2 } < MyInt{ 1 } ), "" );
static_assert( ! static_cast<bool>( MyInt{ 2 } <= MyInt{ 1 } ), "" );
static_assert( MyInt{ 2 } > MyInt{ 1 }, "" );
static_assert( MyInt{ 2 } >= MyInt{ 1 }, "" );
static_assert( MyInt{ 1 } == MyInt{ 1 }, "" );
static_assert( ! static_cast<bool>( MyInt{ 1 } != MyInt{ 1 } ), "" );
static_assert( ! static_cast<bool>( MyInt{ 1 } < MyInt{ 1 } ), "" );
static_assert( MyInt{ 1 } <= MyInt{ 1 }, "" );
static_assert( ! static_cast<bool>( MyInt{ 1 } > MyInt{ 1 } ), "" );
static_assert( MyInt{ 1 } >= MyInt{ 1 }, "" );
#endif
#endif
return boost::report_errors();
}