220 33245 <10063dea-8668-4096-a0da-58a142229e13@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: Tue, 18 Jul 2017 09:57:57 -0700 (PDT)
Lines: 400
Approved: news@gmane.org
Message-ID: <10063dea-8668-4096-a0da-58a142229e13@isocpp.org>
References: <66f9bab2-7220-4bf1-afb7-77c5efa1bac3@isocpp.org>
 <4c552140-4029-4b28-af22-9e2843993516@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_2200_1803443752.1500397077513"
X-Trace: blaine.gmane.org 1500397086 25847 195.159.176.226 (18 Jul 2017 16:58:06 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Tue, 18 Jul 2017 16:58:06 +0000 (UTC)
Cc: federico.kircheis@gmail.com
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCZ3PBGHYEBBBFX4XDFQKGQEIOP2Z7Y@isocpp.org Tue Jul 18 18:58:00 2017
Return-path: <std-proposals+bncBCZ3PBGHYEBBBFX4XDFQKGQEIOP2Z7Y@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-pf0-f200.google.com ([209.85.192.200])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCZ3PBGHYEBBBFX4XDFQKGQEIOP2Z7Y@isocpp.org>)
	id 1dXVoo-00065m-7M
	for gclcip-std-proposals@m.gmane.org; Tue, 18 Jul 2017 18:57:54 +0200
Original-Received: by mail-pf0-f200.google.com with SMTP id p1sf25782017pfl.2
        for <gclcip-std-proposals@m.gmane.org>; Tue, 18 Jul 2017 09:58:00 -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=dHnE2iSbNAnV4TQT2lu4ff2po6GU9qctPsxNWVHcq1I=;
        b=DKeXjBvzqDqPe6MkalEmxPngkPLxtBQKzGijRqnVEUCz6DZV3DVFv+Nrzh+vGOhOkl
         9mrWeiU+mFGEaTA4kZlV2JC5nFJSG5vhUKNlQTQqIV36j6sHbnaWnZaSEbCXyA73WeP2
         JFUq8G8+0SDdPdv77aa6iQEa7psW4ViOrhOpYO8QD9PYdlbfCSzT5gCRZKzHy77VcdWE
         DKPfoliQg7gXmnPYv8acaqNVSLQHQHAu/BnqqT3CDm0qwK3e7fz3hHiMO1AnhgrrnZRt
         e+auXndnjLH+ynRtNV1GbK/O8S+NbZMLuBGZT2NYfaJGqxnxLXSdc3v/ZSUIIxt8dHCb
         zuMw==
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=dHnE2iSbNAnV4TQT2lu4ff2po6GU9qctPsxNWVHcq1I=;
        b=GE6exqWH8i/vHy+2xiNgAEiqM0zacW+dLImTTmuG27beE3m+Qr6BaNuVk+VJ+npVTG
         ME26ATrLawPoKPUdxRlE7+ZWJvnlmAy8bncL65/Mwqz6mdnFN/TDskA8XCg6kHkIA+3e
         bhJzMSy6Oh5FzeDWADcfFEYxnQMMGIUw7mu4RU4bi5MzMtU9lmn41hmX96zCPYvvLBer
         UNOg8Yyeh264wJPEfpCG+96f8B0V8eLlYnWH5MdOdBJ9WCppVSqitiFwZ0rBIFFcYDCl
         x1bYtd8PeKjt66/BOwNM21gXrsiHr+Jl94QxjPjMocpnuoljrsAdrNIyXZuwNZ3qPZHi
         +p/Q==
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=dHnE2iSbNAnV4TQT2lu4ff2po6GU9qctPsxNWVHcq1I=;
        b=JBmbyuvS/5i8W6BoC+VwC4lLjnIxaS2eZ6kKdf78WJEJlGGiP5RWoTdnnSR6u+8CVI
         EqmWgdnEtjy98hHiE5tdffuWrQlRrcICWZG0F9AKE1RUXcd7EmKVEE6Gr+94TyIAO7f0
         OGPjWDlRr5xliWpheqnVFmHNIik9yVGFnE3WwzB/pqKsLNKxO4Q0SfC+/nXkWrj7m++b
         OgvOP9TbVVlP1SnqNb8FXPNL7XP+SUEcJbF+SXb9zk+K+jm2NE1XmCOgm1Cu9bnexJ7B
         dmdu4bwpYRoCye+St9vt02E66mzuqiDeGbCSQOLzW9OwVQFc6eESuH1WQ7hMI0x3jS65
         PSqA==
X-Gm-Message-State: AIVw111tcF5/1o68I3nhjlkomUrq8fu8BjRfgg4XpTi5/UnMRA8qypgN
	mn2qGfFNEp4iC/2s
X-Received: by 10.99.177.67 with SMTP id g3mr1576954pgp.104.1500397079381;
        Tue, 18 Jul 2017 09:57:59 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.36.74.139 with SMTP id k133ls5676588itb.7.canary-gmail; Tue,
 18 Jul 2017 09:57:58 -0700 (PDT)
X-Received: by 10.31.174.216 with SMTP id x207mr9101vke.10.1500397078258;
        Tue, 18 Jul 2017 09:57:58 -0700 (PDT)
In-Reply-To: <4c552140-4029-4b28-af22-9e2843993516@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:33245
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/33245>

------=_Part_2200_1803443752.1500397077513
Content-Type: multipart/alternative; 
	boundary="----=_Part_2201_1963458137.1500397077514"

------=_Part_2201_1963458137.1500397077514
Content-Type: text/plain; charset="UTF-8"

Forgot to attach the new proposal ;-)

On Tuesday, July 18, 2017 at 6:57:04 PM UTC+2, federico...@gmail.com wrote:
>
> Updated the proposal again,
>
> I've removed the precision function, John McFarian was right about 
> "std::numeric_limits<T>::digits" and set the version number to D0586R1, 
> since it is still a draft.
>
>
> is_losslessly_convertible might be a nice compile-time function, but I 
> think that in_range with the std::numeric_limits<T>::max and 
> std::numeric_limits<T>::min value will gave you the same result (and it can 
> of course be used at compile-time too).
>

-- 
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/10063dea-8668-4096-a0da-58a142229e13%40isocpp.org.

------=_Part_2201_1963458137.1500397077514
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Forgot to attach the new proposal ;-)<br><br>On Tuesday, J=
uly 18, 2017 at 6:57:04 PM UTC+2, federico...@gmail.com wrote:<blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
 #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">Updated the proposal again=
,<br><br>I&#39;ve removed the precision function, John McFarian was right a=
bout &quot;std::numeric_limits&lt;T&gt;::<wbr>digits&quot; and set the vers=
ion number to D0586R1, since it is still a draft.<br><br><br>is_losslessly_=
convertible might be a nice compile-time function, but I think that in_rang=
e with the std::numeric_limits&lt;T&gt;::max and std::numeric_limits&lt;T&g=
t;::min value will gave you the same result (and it can of course be used a=
t compile-time too).<br></div></blockquote></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/10063dea-8668-4096-a0da-58a142229e13%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/10063dea-8668-4096-a0da-58a142229e13=
%40isocpp.org</a>.<br />

------=_Part_2201_1963458137.1500397077514--

------=_Part_2200_1803443752.1500397077513
Content-Type: text/html; charset=US-ASCII; name=proposal.html
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=proposal.html
X-Attachment-Id: c59e2312-90c2-4802-b4cb-a663187335f7
Content-ID: <c59e2312-90c2-4802-b4cb-a663187335f7>

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>Safe integral comparisons</title>
	</head>
	<body>
		<address>
			Document number: D0586R1<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="#Implementation" >V).......Possible 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 (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>


		<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="Implementation">V. Possible implementation</h2>
			<p>
				This section shows an example of how <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.
				This implementation can also be found on <a href="https://raw.githubusercontent.com/fekir/safeintegral/master/safeintegral/safeintegralop_cmp.hpp">github</a>.
			</p>

<pre><code>
	#include &lt;limits&gt;
	#include &lt;type_traits&gt;

	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;
	}

	// 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 (std::numeric_limits&lt;T&gt;::digits  &gt; std::numeric_limits&lt;R&gt;::digits ) ?
		    (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 (std::numeric_limits&lt;T&gt;::digits  &gt; std::numeric_limits&lt;R&gt;::digits ) ?
		    (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 :
		    (std::numeric_limits&lt;T&gt;::digits  / 2 &lt;= std::numeric_limits&lt;R&gt;::digits ) ? 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 (std::numeric_limits&lt;T&gt;::digits  &gt;= std::numeric_limits&lt;R&gt;::digits  / 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 (std::numeric_limits&lt;T&gt;::digits &gt; std::numeric_limits&lt;U&gt;::digits ) ? (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 : (std::numeric_limits&lt;T&gt;::digits  / 2&gt; std::numeric_limits&lt;U&gt;::digits  ) ? (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 (std::numeric_limits&lt;T&gt;::digits &gt;std::numeric_limits&lt;U&gt;::digits ) ? (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 : (std::numeric_limits&lt;T&gt;::digits  / 2&gt;std::numeric_limits&lt;U&gt;::digits ) ? (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 : (std::numeric_limits&lt;U&gt;::digits  / 2&gt;std::numeric_limits&lt;T&gt;::digits ) ? (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

	/// 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>&lt;=&gt;</code>).
				As far as I've understood the proposal the <code>operator&lt;=&gt;</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_2200_1803443752.1500397077513--

.
