220 32913 <98e56e58-69bd-49f0-945c-aa6e7b6b4abb@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, 27 Jun 2017 10:00:55 -0700 (PDT)
Lines: 396
Approved: news@gmane.org
Message-ID: <98e56e58-69bd-49f0-945c-aa6e7b6b4abb@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_2355_81630189.1498582855788"
X-Trace: blaine.gmane.org 1498582864 27852 195.159.176.226 (27 Jun 2017 17:01:04 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Tue, 27 Jun 2017 17:01:04 +0000 (UTC)
Cc: federico.kircheis@gmail.com
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCZ3PBGHYEBBBSE6ZLFAKGQEFQYOVOY@isocpp.org Tue Jun 27 19:00:57 2017
Return-path: <std-proposals+bncBCZ3PBGHYEBBBSE6ZLFAKGQEFQYOVOY@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-yw0-f200.google.com ([209.85.161.200])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCZ3PBGHYEBBBSE6ZLFAKGQEFQYOVOY@isocpp.org>)
	id 1dPtrB-0006fM-Dt
	for gclcip-std-proposals@m.gmane.org; Tue, 27 Jun 2017 19:00:53 +0200
Original-Received: by mail-yw0-f200.google.com with SMTP id c13sf23792156ywa.13
        for <gclcip-std-proposals@m.gmane.org>; Tue, 27 Jun 2017 10:00:59 -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=2gQgqI9U6Mhd0/TCF+NUD2qvVdC36MeM1wlXHWbCHFI=;
        b=BxjDkK7oqI40xyHyDvlqIZz0CYkJxkxsWlemr5QDboNmWR/XwoG7cOJHgU1XVq8rwg
         OvFwAFaxqvcCxLyMzB0apgkFaRXjkTdeAryz0Ekbeobrl4zVmZPsqiO5shEAEG2HW0mh
         oiBJtdBOqSlk8krx678dGkcP+NL9KLhUyAVSgp7vZJPkxbOL0FPkS5AlPXWjcFhyO9wB
         F0zlPhxRoQs3gZ+YRMhqMhlqO5hOPfa8PAoqRrtFK1JZUVarNV5BCAj6iU11x2W/gprv
         7X7NdvhQgDyRtJt1EdqsZdtW1/VtZrrSWyR46TUllId4FxbDBClB+4ltnHdWTT4eGhRv
         Ofjg==
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=2gQgqI9U6Mhd0/TCF+NUD2qvVdC36MeM1wlXHWbCHFI=;
        b=tph+OjPRAA8jJte+ZLfWX9chw8hgvexFfbmGGTYaWaZ8o09Oc6jzfoo5xHtHR6lKbs
         ZfwWBMQdM6f3jGa855GT9krD1OVt1mLGGkglkVOCwlAjeqVXKrWQ9QC1A6jhi5BD+sPz
         jUNAxaJbClq/qcL8/4fSkBvFolks+1dfR62Dno6JCXKOP1icl1IJhzVYsmS9mZ+AKLH0
         nTCXM7yM/t8ULbYu+Qh0X52txdLYvnOxQQks3neAOkZII/XOuZ5rhSugSsrucwrvVHJ8
         wZCuc7SN2LgALT21MSvbYF37Y+Tx3h5/HtHojQ+yTHr47cODq2EKBQl+XrYyewXFXyWn
         yi3w==
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=2gQgqI9U6Mhd0/TCF+NUD2qvVdC36MeM1wlXHWbCHFI=;
        b=l5E4LGmVus0WBXZo8pfRYQIOlp929CMHJWMMazEWt7WG5mKS6cqV7HJjrtT0OZd5GB
         gv0E5lnw5ONvkTHstBo/0cCiiZSP6BM/nzyjj8ueetxB9hvIxykAbfV40aUhrOSXQt0l
         1D4ZLh77hpJVCPiP/NIBEVUdaiMlszBaclECriTGPJQdgTc0C+JXJ3asIm50Jt1X/h9n
         PbjfuEHrh2kJ2q+lIhNmBTxtFTZPQvb0djF95DZ0wzVbH1k8b8JEFFvg4OuCizOuSWOY
         mRRWcVfk4NFhkEVYLi8G+NbvATinX+twfswsfbkswLu0qx27CBrEDMl1q3PEXl0Hhi20
         a9LQ==
X-Gm-Message-State: AKS2vOzGmmy7q3D5HpwqHYQcvnE4WYLmj5AgTKtIMcIWqsSXaiQ44EOZ
	+2/MnD/citLxMAfP
X-Received: by 10.129.33.130 with SMTP id h124mr3639663ywh.125.1498582858350;
        Tue, 27 Jun 2017 10:00:58 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.36.58.17 with SMTP id m17ls912347itm.16.canary-gmail; Tue, 27
 Jun 2017 10:00:56 -0700 (PDT)
X-Received: by 10.36.79.144 with SMTP id c138mr50250itb.2.1498582856485;
        Tue, 27 Jun 2017 10:00:56 -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:32913
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/32913>

------=_Part_2355_81630189.1498582855788
Content-Type: multipart/alternative; 
	boundary="----=_Part_2356_678608755.1498582855788"

------=_Part_2356_678608755.1498582855788
Content-Type: text/plain; charset="UTF-8"

I've updated my proposal (Proposal number is P0586R0).

Just fixed some minor issues and added the proposal number, the content is 
the same.

-- 
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/98e56e58-69bd-49f0-945c-aa6e7b6b4abb%40isocpp.org.

------=_Part_2356_678608755.1498582855788
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I&#39;ve updated my proposal (Proposal number is P0586R0).=
<br><br>Just fixed some minor issues and added the proposal number, the con=
tent is the same.<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/98e56e58-69bd-49f0-945c-aa6e7b6b4abb%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/98e56e58-69bd-49f0-945c-aa6e7b6b4abb=
%40isocpp.org</a>.<br />

------=_Part_2356_678608755.1498582855788--

------=_Part_2355_81630189.1498582855788
Content-Type: text/html; charset=US-ASCII; name=proposal.html
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=proposal.html
X-Attachment-Id: c20d09fd-08a4-4bc3-b11f-36e733ccb8a1
Content-ID: <c20d09fd-08a4-4bc3-b11f-36e733ccb8a1>

<!DOCTYPE html>
<html>
	<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>

		<a name="Table"></a><h2>I. Table of Contents</h2>
		<ul>
			<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="#Sample">V. Sample implementation</a></li>
			<li><a href="#Effects">VI. Effects on Existing Code</a></li>
			<li><a href="#Design">VII. Design Decisions</a></li>
		</ul>


		<a name="Motivation"></a><h2>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
<blockquote><pre>
if(a &lt; b){
	// ...
} else {
	// ...
}
</pre></blockquote>
should work in all cases, but if a and b 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.</br>
		</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
<blockquote><pre>
a = static_cast&lt;decltype(a)&gt;(b);
</pre></blockquote>
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>



		<a name="Proposal"></a><h2>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>):

			<ul>
				<li>
Two functions to compare if two variables represent the same value or not
<blockquote><pre>
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;
</pre></blockquote>


				<li>
A set of functions that can be used to determine the relative order of two values
<blockquote><pre>
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;
</pre></blockquote>

				<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)
<blockquote><pre>
template &lt;typename R, typename T&gt;
constexpr bool in_range(T t) noexcept;
</pre></blockquote>

				<li>
One function for retrieving the precision of a given numeric type
<blockquote><pre>
template &lt;typename T&gt;
constexpr std::size_t std::precision() noexcept;
</pre></blockquote>

			</ul>
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>
<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>


		<a name="Examples"></a><h2>IV. Examples</h2>
		<h3>Examples without current proposal</h3>
		<p>
Comparing an unsigned int with an int:
<blockquote><pre>
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
}
</pre></blockquote>

Comparing an uint32_t with an int16_t:
<blockquote><pre>
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
}
</pre></blockquote>

Comparing an int with an intptr_t:
<blockquote><pre>
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
}
</pre></blockquote>


		<h3>Example with current proposal</h3>
Comparing one integral type <code>A</code> with another integral type <code>B</code> (both non <code>bool</code>):
<blockquote><pre>
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
}
</pre></blockquote>

		</p>
		<a name="Sample"></a><h2>V. Sample 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, without any language extension. 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.

<blockquote><pre>

#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);
}
</pre></blockquote>

		</p>

		<a name="Effects"></a><h2>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>

		<a name="Design"></a><h2>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>
	</body>
</html>

------=_Part_2355_81630189.1498582855788--

.
