220 33220 <4a572c09-5142-4834-a907-93c3cc87e79c@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: federico.kircheis@gmail.com
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: safe integrals comparison
Date: Sun, 16 Jul 2017 01:00:17 -0700 (PDT)
Lines: 420
Approved: news@gmane.org
Message-ID: <4a572c09-5142-4834-a907-93c3cc87e79c@isocpp.org>
References: <66f9bab2-7220-4bf1-afb7-77c5efa1bac3@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_538_349762377.1500192018086"
X-Trace: blaine.gmane.org 1500192028 19087 195.159.176.226 (16 Jul 2017 08:00:28 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Sun, 16 Jul 2017 08:00:28 +0000 (UTC)
Cc: federico.kircheis@gmail.com
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCZ3PBGHYEBBBE52VTFQKGQEXHD674Y@isocpp.org Sun Jul 16 10:00:21 2017
Return-path: <std-proposals+bncBCZ3PBGHYEBBBE52VTFQKGQEXHD674Y@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-yw0-f198.google.com ([209.85.161.198])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCZ3PBGHYEBBBE52VTFQKGQEXHD674Y@isocpp.org>)
	id 1dWeTP-0004Ng-55
	for gclcip-std-proposals@m.gmane.org; Sun, 16 Jul 2017 10:00:15 +0200
Original-Received: by mail-yw0-f198.google.com with SMTP id c13sf82996774ywa.13
        for <gclcip-std-proposals@m.gmane.org>; Sun, 16 Jul 2017 01:00:20 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:cc:message-id:in-reply-to:references:subject
         :mime-version:x-original-sender:reply-to:precedence:mailing-list
         :list-id:list-post:list-help:list-archive:list-subscribe
         :list-unsubscribe;
        bh=yIdJNqMwrWbUVSDHYwtmaymZwi6eOFihz5RGQipibzk=;
        b=lTg7w8v2Qn3y14IQqnPPNiJsD7RBbYg1QjjFwJ1ugSc5q8jHMFO51WpQ/mdoAQm8Vm
         aYZ2y44FqZTVM3+53w+y0PohcIcsIbFlnJezuLmnJoLGTKqY49+j5RGMCY8PWgiuE7a+
         akWCqbPAO6c5j+FYVLdp+sJbS85YIJobHZnYlegr9m1kaa7lW752auYD9ZhgDggTc6qi
         8iwxDjIljwclNaG1LWFBE9XH92v4gqfEt2kYNlaZK2G2J9+8GRut30bRcILMIQpeObjJ
         GzgxOJymwRj70td1kFkwdzEk2m6VSN9TdkMgmMccLd4NdXt4+6B6az4Qh+Tt7zI5h77E
         mXBA==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=date:from:to:cc:message-id:in-reply-to:references:subject
         :mime-version:x-original-sender:reply-to:precedence:mailing-list
         :list-id:list-post:list-help:list-archive:list-subscribe
         :list-unsubscribe;
        bh=yIdJNqMwrWbUVSDHYwtmaymZwi6eOFihz5RGQipibzk=;
        b=q7Hcf7R/jctYHI8PNjGERkfpqI3LQRMfE12qinRJvFLblW93eU9L4iDj8NECnGFJc5
         7VlV68QMdJoaR9pxkTxBz1xL8CCviYCf1LfjXiUEI+lvOQutbbjGLu0IkjJrzAJ9hwDJ
         EBbfRwYTS1ZQybeM4pBBkhVn+PqfKySwmpdhqNQujAJhihh7chxcwb5PJ45yzhUJ9aSS
         MtqwBt0T1l7TSlHPa1/JUvY+t0UwZeg45sdWjlK7kTtt0ALtHonX1W+t7ReVlZijh4B0
         3OFjkUUsM8ILga7A9wcTDVe5xdyhHoQ8Ot0/YQatzFki3EoxKPMzfN0/5LjwSDPdrNdc
         0QIA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:date:from:to:cc:message-id:in-reply-to
         :references:subject:mime-version:x-original-sender:reply-to
         :precedence:mailing-list:list-id:x-spam-checked-in-group:list-post
         :list-help:list-archive:list-subscribe:list-unsubscribe;
        bh=yIdJNqMwrWbUVSDHYwtmaymZwi6eOFihz5RGQipibzk=;
        b=L8ubeHtMT3o/pRlC8r/bBAEUM3c/EHBOrZCvLfuFU8+O0wuZXY2wHFSMMJzOGG96OM
         eqvjo2/vrdhAieV+sjIx13ju3dqr5zeuItgyBrVXSlFW1wNMUheqqrGQLuCvcQu/bQkk
         iAKXx64hpV8fLxLdU6DmUw2EFCawAI9x24FYoys5GkkUz0WipMLMlwQi4L4exqV4F5Ty
         Zcg/yJakPrCQ2TYTXZjFXVzjBYvVu8o/Y9fd+Oz7iBVlKiKNp18z8R/mCGLAkUxJMhFO
         pYjWaOySpXv4a4LBNuJDtQ1KAFDqeGSz9YF5Nb1GaCoq0RDSqgp059zCZZE9lStvip+a
         ZADQ==
X-Gm-Message-State: AIVw11396LJs98FLEyNWrXeRt+J8BZxXWHTbKAhffhzeH2/ydKKohvEG
	0r5cioaitQ+yo8kG
X-Received: by 10.129.172.104 with SMTP id z40mr10554898ywj.29.1500192020331;
        Sun, 16 Jul 2017 01:00:20 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.36.91.20 with SMTP id g20ls3646391itb.6.gmail; Sun, 16 Jul
 2017 01:00:18 -0700 (PDT)
X-Received: by 10.31.99.134 with SMTP id x128mr58587vkb.3.1500192018800;
        Sun, 16 Jul 2017 01:00:18 -0700 (PDT)
In-Reply-To: <66f9bab2-7220-4bf1-afb7-77c5efa1bac3@isocpp.org>
X-Original-Sender: federico.kircheis@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:33220
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/33220>

------=_Part_538_349762377.1500192018086
Content-Type: multipart/alternative; 
	boundary="----=_Part_539_1765635022.1500192018087"

------=_Part_539_1765635022.1500192018087
Content-Type: text/plain; charset="UTF-8"

Another update to the proposal,

I've added the references to Robert Ramey's proposal (and a link to an 
alternative implementation of the comparison functions in his github 
repository) and Herb Sutter's proposal for operator<=>.

-- 
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/4a572c09-5142-4834-a907-93c3cc87e79c%40isocpp.org.

------=_Part_539_1765635022.1500192018087
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Another update to the proposal,<br><br>I&#39;ve added the =
references to Robert Ramey&#39;s proposal (and a link to an alternative imp=
lementation of the comparison functions in his github repository) and Herb =
Sutter&#39;s proposal for operator&lt;=3D&gt;.<br></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/4a572c09-5142-4834-a907-93c3cc87e79c%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/4a572c09-5142-4834-a907-93c3cc87e79c=
%40isocpp.org</a>.<br />

------=_Part_539_1765635022.1500192018087--

------=_Part_538_349762377.1500192018086
Content-Type: text/html; charset=US-ASCII; name=proposal.html
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=proposal.html
X-Attachment-Id: 1746a96f-c239-4a45-b6af-058adc3784f5
Content-ID: <1746a96f-c239-4a45-b6af-058adc3784f5>

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>Safe integral comparisons</title>
	</head>
	<body>
		<address>
			Document number: P0586R0<br/>
			Date: 2017-02-04<br/>
			Project: Programming Language C++<br/>
			Reply-to: <a href="mailto:federico.kircheis@gmail.com">Federico Kircheis</a><br/>
		</address>

		<h1>Safe integral comparisons</h1>

		<h2 id="Table">I. Table of Contents</h2>
		<ul style="font-family:monospace">
			<li><a href="#Table"       >I).......Table of Contents</a></li>
			<li><a href="#Motivation"  >II)......Motivation</a></li>
			<li><a href="#Proposal"    >III).....Proposal</a></li>
			<li><a href="#Examples"    >IV)......Examples</a></li>
			<li><a href="#Example"      >V)......Example implementation</a></li>
			<li><a href="#Effects"     >VI)......Effects on Existing Code</a></li>
			<li><a href="#Design"      >VII).....Design Decisions</a></li>
			<li><a href="#Related"     >VIII)....Related Works</a></li>
		</ul>


		<h2 id="Motivation">II. Motivation</h2>

		<p>
			Comparing integrals of different types may be a more complex task than expected. Most of the time we expect that a simple
		</p>
<pre><code>	if(a &lt; b){
		// ...
	} else {
		// ...
	}
</code></pre>
		<p>
			should work in all cases, but if <code>a</code> and <code>b</code> are of different types, things are more complicated.<br/>
			If <code>a</code> is a signed type, and <code>b</code> unsigned, then <code>a</code> is converted to the unsigned type.
			If <code>a</code> held a number less than zero, then the result may be unexpected, since the expression <code>a &lt; b</code> could evaluate to false, even if a strictly negative number is always lower than a positive one.
		</p>

		<p>
			Also converting integrals between different types can be challenging, for simplicity, most of the time we assume that values are in range, and write
		</p>
<pre><code>	a = static_cast&lt;decltype(a)&gt;(b);</code></pre>
		<p>
			If we want to write a safe conversion, we need to check if <code>b</code> has a value between <code>std::numeric_limits&lt;decltype(a)&gt;::min()</code> and <code>std::numeric_limits&lt;decltype(a)&gt;::max()</code>.
			We also need to pay attention that no implicit conversion (for example between unsigned and signed types) invalidates our comparison.
		</p>

		<p>
			Comparing and converting numbers, even of different numeric types, should be a trivial task.
			Unfortunately it is not, and because of implicit conversions we may write, without noticing it, unsafe code.
		</p>

		<h2 id="Proposal">III. Proposal</h2>

		<p>
			This paper proposes to add a set of <code>constexpr</code> and <code>noexcept</code> functions for converting and comparing integrals of different signeddes and precision (except for <code>bool</code>):
		</p>

		<ul>
			<li>
				Two functions to compare if two variables represent the same value or not
<pre><code>	template &lt;typename T, typename U&gt;
	constexpr bool std::cmp_equal(T t, U u) noexcept;

	template &lt;typename T, typename U&gt;
	constexpr bool std::cmp_unequal(T t, U u) noexcept;
</code></pre>


			<li>
				A set of functions that can be used to determine the relative order of two values
<pre><code>	template &lt;typename T, typename U&gt;
	constexpr bool std::cmp_less(T t, U u) noexcept;

	template &lt;typename T, typename U&gt;
	constexpr bool std::cmp_greater(T t, U u) noexcept;

	template &lt;typename T, typename U&gt;
	constexpr bool std::cmp_less_or_equal(T t, U u) noexcept;

	template &lt;typename T, typename U&gt;
	constexpr bool std::cmp_greater_or_equal(T t, U u) noexcept;
</code></pre>

			<li>
				One function to determine if a specific value is inside the range of possible values of another type (i.e. if we can convert the value to the other type safely)
<pre><code>	template &lt;typename R, typename T&gt;
	constexpr bool in_range(T t) noexcept;
</code></pre>

			<li>
				One function for retrieving the precision of a given numeric type
<pre><code>
	template &lt;typename T&gt;
	constexpr std::size_t std::precision() noexcept;
</code></pre>

		</ul>
		<p>
			The function <code>precision</code> is part of the proposal because we cannot use the operator <code>sizeof</code> to determine between two types which one has a wider range (quote from <a href="https://www.securecoding.cert.org/confluence/display/c/INT35-C.+Use+correct+integer+precisions">SecureCoding</a>):<br/>
		</p>
		<q>
			Integer types in C have both a size and a precision.
			The size indicates the number of bytes used by an object and can be retrieved for any object or type using the sizeof operator.
			The precision of an integer type is the number of bits it uses to represent values, excluding any sign and padding bits.
			Padding bits contribute to the integer's size, but not to its precision.
			Consequently, inferring the precision of an integer type from its size may result in too large a value, which can then lead to incorrect assumptions about the numeric range of these types.
			Programmers should use correct integer precisions in their code, and in particular, should not use the sizeof operator to compute the precision of an integer type on architectures that use padding bits or in strictly conforming (that is, portable) programs.
		</q>

		<p>
			The <code>precision</code> function does not have to be part of the proposal, but it seems an useful addition.
		</p>


		<h2 id="Examples">IV. Examples</h2>
			<h3>Examples without current proposal</h3>
				<p>Comparing an unsigned int with an int:</p>
<pre><code>	int a = ...
	unsigned int b = ...
	// added static_cast to avoid compiler warnings since we are doing a "safe" comparison
	if(a &lt; 0 || static_cast&lt;unsigned int&gt;(a) &lt; b){
		// do X
	} else {
		// do Y
	}
</code></pre>

				<p>Comparing an uint32_t with an int16_t:</p>
<pre><code>	int32_t a = ...
	uint16_t b = ...
	// added static_cast to avoid compiler warnings since we are doing a "safe" comparison
	if(a &lt; static_cast&lt;int32_t&gt;(b)){
		// do X
	} else {
		// do Y
	}
</code></pre>

				<p>Comparing an int with an intptr_t:</p>
<pre><code>	int a = ...
	intptr_t b = ...
	if(???){ // no idea how to do it in one readable line without some assumption about int and intptr_t
		// do X
	} else {
		// do Y
	}
</code></pre>


			<h3>Example with current proposal</h3>
				<p>
					Comparing one integral type <code>A</code> with another integral type <code>B</code> (both non <code>bool</code>):
				</p>
<pre><code>	A a = ...
	B b = ...
	// no need for any cast since std::cmp_less is taking care of everything
	if( std::cmp_less(a,b)){
		// do X
	} else {
		// do Y
	}
</code></pre>

		<h2 id="Example">V. Example implementation</h2>
			<p>
				This section shows an example of how <code>precision</code>, <code>cmp_equal</code>, <code>cmp_less</code> and <code>in_range</code> can be implemented with any standard conforming C++11 compiler.
				The only dependencies are the <code>std::numeric_limits</code> function from the <code>limits</code> header and some traits from the <code>type_traits</code> header.
			</p>

<pre><code>
	#include &lt;limits&gt;
	#include &lt;type_traits&gt;

	template &lt;typename T&gt;
	constexpr std::size_t precision() noexcept;

	namespace details{
	#if defined(ERR_MSG_xxx_NEEDS_INTEGRAL_NOT_BOOL) || defined(ASSERT_INTEGRAL_NOT_BOOL_TYPE)
	#error "ERR_MSG_xxx_NEEDS_INTEGRAL_NOT_BOOL or ASSERT_INTEGRAL_NOT_BOOL_TYPE already defined"
	#endif
	#define ERR_MSG_xxx_NEEDS_INTEGRAL_NOT_BOOL " needs to be an integral (not bool) value type"
	#define ASSERT_INTEGRAL_NOT_BOOL_TYPE(T) static_assert(is_integral_not_bool&lt;T&gt;(), #T ERR_MSG_xxx_NEEDS_INTEGRAL_NOT_BOOL);

	template &lt;typename T&gt;
	constexpr bool is_integral_not_bool(){
		using value_type = typename std::remove_cv&lt;T&gt;::type;
		return !std::is_same&lt;value_type,bool&gt;::value && std::is_integral&lt;T&gt;::value;
	}

	template &lt;class T&gt;
	constexpr std::size_t pop(const std::size_t precision, const T num) {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		return (num == T{0}) ? precision : pop(((num % 2 != 0) ? precision+1 : precision), num &gt;&gt; 1);
	}


	// could use the same implementation of in_range_signed_signed, but compiler may generate warning that t is always bigger than 0
	template &lt;typename R, typename T&gt;
	constexpr bool in_range_unsigned_unsigned(const T t) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(R);
		return (precision&lt;T&gt;() &gt; precision&lt;R&gt;()) ?
		    (t &lt; static_cast&lt;T&gt;(std::numeric_limits&lt;R&gt;::max())) :
		    (static_cast&lt;R&gt;(t) &lt;std::numeric_limits&lt;R&gt;::max());
	}

	template &lt;typename R, typename T&gt;
	constexpr bool in_range_signed_signed(const T t) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(R);
		return (precision&lt;T&gt;() &gt; precision&lt;R&gt;()) ?
		    (t &lt;= static_cast&lt;T&gt;(std::numeric_limits&lt;R&gt;::max()) && t &gt;= static_cast&lt;T&gt;(std::numeric_limits&lt;R&gt;::min())) :
		    (static_cast&lt;R&gt;(t) &lt;= std::numeric_limits&lt;R&gt;::max() && static_cast&lt;R&gt;(t) &gt;= std::numeric_limits&lt;R&gt;::max());
	}

	template &lt;typename R, typename T&gt;
	constexpr bool in_range_signed_unsigned(const T t) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(R);
		return (t &lt; T{ 0 }) ? false :
		    (precision&lt;T&gt;() / 2 &lt;= precision&lt;R&gt;()) ? true :
		    (t &lt;= static_cast&lt;T&gt;(std::numeric_limits&lt;R&gt;::max()));
	}

	template &lt;typename R, typename T&gt;
	constexpr bool in_range_unsigned_signed(const T t) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(R);
		return (precision&lt;T&gt;() &gt;= precision&lt;R&gt;() / 2) ? (t &lt;= static_cast&lt;T&gt;(std::numeric_limits&lt;R&gt;::max())) : true;
	}

	template &lt;typename R, typename T&gt;
	constexpr bool in_range_unsigned(const T t) noexcept {
		return std::is_unsigned&lt;R&gt;::value ? in_range_unsigned_unsigned&lt;R&gt;(t) : in_range_unsigned_signed&lt;R&gt;(t);
	}

	template &lt;typename R, typename T&gt;
	constexpr bool in_range_signed(const T t) noexcept {
		return std::is_signed&lt;R&gt;::value ? in_range_signed_signed&lt;R&gt;(t) : in_range_signed_unsigned&lt;R&gt;(t);
	}

	template &lt;typename T, typename U&gt;
	constexpr bool cmp_equal_same_sign(const T t, const U u) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(U);
		return (precision&lt;T&gt;()&gt;precision&lt;U&gt;()) ? (t == static_cast&lt;T&gt;(u)) : (static_cast&lt;U&gt;(t) == u);
	}

	template &lt;typename T, typename U&gt;
	constexpr bool cmp_equal_signed_unsigned(const T t, const U u) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(U);
		return (t&lt;T{ 0 }) ? false : (precision&lt;T&gt;() / 2&gt;precision&lt;U&gt;()) ? (t == static_cast&lt;T&gt;(u)) : (static_cast&lt;U&gt;(t) == u);
	}

	template &lt;typename T, typename U&gt;
	constexpr bool cmp_less_same_sign(const T t, const U u) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(U);
		return (precision&lt;T&gt;()&gt;precision&lt;U&gt;()) ? (t &lt; static_cast&lt;T&gt;(u)) : (static_cast&lt;U&gt;(t) &lt; u);
	}

	template &lt;typename T, typename U&gt;
	constexpr bool cmp_less_signed_unsigned(const T t, const U u) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(U);
		return (t&lt;T{ 0 }) ? true : (precision&lt;T&gt;() / 2&gt;precision&lt;U&gt;()) ? (t &lt; static_cast&lt;T&gt;(u)) : (static_cast&lt;U&gt;(t) &lt; u);
	}

	template &lt;typename T, typename U&gt;
	constexpr bool cmp_less_unsigned_signed(const T t, const U u) noexcept {
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(T);
		ASSERT_INTEGRAL_NOT_BOOL_TYPE(U);
		return (u&lt;U{ 0 }) ? false : (precision&lt;U&gt;() / 2&gt;precision&lt;T&gt;()) ? (static_cast&lt;U&gt;(t) &lt; u) : (t &lt; static_cast&lt;T&gt;(u));
	}

	#undef ERR_MSG_xxx_NEEDS_INTEGRAL_NOT_BOOL
	#undef ASSERT_INTEGRAL_NOT_BOOL_TYPE
	} // end details

	template &lt;typename T&gt;
	constexpr std::size_t precision() noexcept {
		return details::pop(0, std::numeric_limits&lt;T&gt;::max());
	}

	/// Usage:
	/// size_t i = ...
	/// if(in_range&lt;DWORD&gt;(i)){
	///  // safe to use i as a DWORD value, parameter...
	/// } else {
	///  // not possible to rappresent i as a DWORD
	/// }
	template &lt;typename R, typename T&gt;
	constexpr bool in_range(const T t) noexcept {
		return std::is_unsigned&lt;T&gt;::value ? details::in_range_unsigned&lt;R&gt;(t) : details::in_range_signed&lt;R&gt;(t);
	}

	// equivalent of operator== for different types
	/// Usage:
	/// size_t i = ...
	/// DWORD j = ...
	/// if(cmp_equal(i,j)){
	///  // i and j rappresent the same quantity
	/// } else {
	///  // i and j rappresents different quantities
	/// }
	template &lt;typename T, typename U&gt;
	constexpr bool cmp_equal(const T t, const U u) noexcept {
		return
		    (std::is_signed&lt;T&gt;::value == std::is_signed&lt;U&gt;::value) ? details::cmp_equal_same_sign(t, u) :
		    (std::is_signed&lt;T&gt;::value) ? details::cmp_equal_signed_unsigned(t, u) : details::cmp_equal_signed_unsigned(u,t);
	}

	// equivalent of operator&lt; for different integral types
	/// Usage:
	/// size_t i = ...
	/// DWORD j = ...
	/// if(cmp_less(i,j)){
	///  // i &lt; j
	/// } else {
	///  // i &gt;= j
	/// }
	template &lt;typename T, typename U&gt;
	constexpr bool cmp_less(const T t, const U u) noexcept {
		return
		    (std::is_signed&lt;T&gt;::value == std::is_signed&lt;U&gt;::value) ? details::cmp_less_same_sign(t,u) :
		    (std::is_signed&lt;T&gt;::value) ? details::cmp_less_signed_unsigned(t, u) : details::cmp_less_unsigned_signed(t, u);
	}
</code></pre>

		<h2 id="Effects">VI. Effects on Existing Code</h2>
			<p>
				Since the proposed functions are not defined in any standard header, no currently existing code behavior will be changed.
			</p>

		<h2 id="Design">VII. Design Decisions</h2>
			<p>
				Since there is no reason to compare <code>true</code> and <code>false</code> with other integral types, there isn't one to provide an overload for the <code>bool</code> integral type either.<br/>
				The name of the functions (<code>cmp_equal</code>, <code>cmp_less</code> and others) are open to discussion, but the function names <code>std::less</code> and <code>std::greater</code> should not be used, since these do already exist, and have a different meaning.
			</p>

		<h2 id="Related">VIII. Related Works</h2>
			<p>
				In 2016, Robert Ramey did a much bigger proposal (see <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0228r0.pdf">p0228r0</a>) regaridng safe integer types.
				He also used similar functions proposed in this paper for implementing his classes and operators, therefore an alternative implementation can be found on his <a href="https://github.com/robertramey/safe_numerics/blob/master/include/safe_compare.hpp">github repository</a>.
				This proposal addresses a smaller problem, namely comparing integral values, and is therefore much smaller.<br/>
				The functions provided can be also used for creating safe integer types.
			</p>

			<p>
				Another work, by Herb Sutter (see <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0515r0.pdf">p0515r0</a>), is about a new comparison operator (<code><=></code>).
				As far as I've understood the proposal the <code>operator<=></code> should compare correctly different integral types, making part of this proposal obsolete if the operator is added to the language.
				While it would be a nice thing to have, having a new comparison operator that operates differently from the old operators may be counterintuitive and cause confusion, even if the new behaviour is more correct.
			</p>
	</body>
</html>

------=_Part_538_349762377.1500192018086--

.
