220 30771 <845d8ffe-13e2-4597-882c-0404ad582cef@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: Sat, 4 Feb 2017 09:27:38 -0800 (PST)
Lines: 392
Approved: news@gmane.org
Message-ID: <845d8ffe-13e2-4597-882c-0404ad582cef@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_893_515332329.1486229258407"
X-Trace: blaine.gmane.org 1486229260 7593 195.159.176.226 (4 Feb 2017 17:27:40 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Sat, 4 Feb 2017 17:27:40 +0000 (UTC)
Cc: federico.kircheis@gmail.com
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCZ3PBGHYEBBBC463DCAKGQEJWEGBRY@isocpp.org Sat Feb 04 18:27:35 2017
Return-path: <std-proposals+bncBCZ3PBGHYEBBBC463DCAKGQEJWEGBRY@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-ot0-f200.google.com ([74.125.82.200])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCZ3PBGHYEBBBC463DCAKGQEJWEGBRY@isocpp.org>)
	id 1ca47a-0001kj-JW
	for gclcip-std-proposals@m.gmane.org; Sat, 04 Feb 2017 18:27:35 +0100
Original-Received: by mail-ot0-f200.google.com with SMTP id 65sf46075263otq.2
        for <gclcip-std-proposals@m.gmane.org>; Sat, 04 Feb 2017 09:27:40 -0800 (PST)
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:x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=qx9xHXqLLLGtsUGEYHTWGKpQS/FI6ia+Hu253gSeBzs=;
        b=HGoqoB43oXSfruFTI6OOkvWYh09RUZ+F5hc7oquc8lW09II2QEgnnOn7scspIAt4FR
         qFPT2nTROpecBxgJkMvplh4FbzWJPHQT8oUCLMBk34UsS7aYFyoZ7VNx/dziPS/CtH6T
         iYYy2eJNmuuAuQ+pD06Un89VRl6QiGpLdY8EPWRoG0Wmk3bX8UQWK0+PB2hUqrruLQMP
         Wd+sM6M/eOsb22wPG7/fmXIxNZ6f02dP2T8RdExeMha4g7WTH/hXlf7v0wxGZCe7tdLY
         9GLAKOPIVSf95LccGwhN1HwrDW2db6U38lyA+ywa03K3uSWz/5rp+2Z1aY9Rj3NXGtdi
         A4Hw==
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:x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=qx9xHXqLLLGtsUGEYHTWGKpQS/FI6ia+Hu253gSeBzs=;
        b=tO5kRksFRAbts+hyezUtghfdbcfE0AqxizWlxGN+c038I2nF6Uv3OFRaPat8eUoQS9
         jEqGCZ7gQajVxmgO29iMcq3MRpjyz+BxP3PSm8c1PleUNvn9rrlNOacFwTjSd7c6wMpd
         TXJJw8x5sGVglJs+uni6tod4vYr1zH+zSWAiz73i6j2SgM/BWoPP20CnwWcS2Gtf/yRk
         szv1eMlmUjizJIYxh3BRst0bmlGSeeaptO0pWNsm4bQa8dtFgJDkmTIq0fk9vE9rl3g3
         OtER/HZUMGzlQrCq+YtNEuBXrvZz31wMj0S9GBfUqx+dRLUlwWOjWYLio0dp8nEn7tGW
         jqNA==
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=qx9xHXqLLLGtsUGEYHTWGKpQS/FI6ia+Hu253gSeBzs=;
        b=IwpUqun+sP37QJ4A9R6w1kpqIZ2I8QgQm9Y8mMr0za+vcBNL5e763vpfL9YiHZnfkd
         z+tQ2YEHiksT5scZUoZ8Tm8DUYKDII8R5d8QAWf1tUHvCZhTFafhNkynnkNS1HwhUGc+
         CBIkzzfnJGGYxgsmY3aJJcntIwngQpgGUJImQyizNtaiy6UfX5xlbNMzMnN2axPK8zVv
         TjujTA25FmXgOLunSXNWVnfNXCpCg27zlX+sZXd68bK9lCqVzKbPcWVQ7ETYmKu5Ca51
         sJSQAAMmBC1BiJpa14ku2qAIkPh9pMkBqJzp2OPmeha82K7w5cAFcemOGw87ohhc9r9G
         1Jag==
X-Gm-Message-State: AIkVDXKEp0Ww4O06+MOMxuj1Ygq4JrPAt4jSExDUGh+vYVeRb+6n52+1nJXmEFjBjXrYMA==
X-Received: by 10.157.25.197 with SMTP id k63mr629211otk.93.1486229259742;
        Sat, 04 Feb 2017 09:27:39 -0800 (PST)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.157.46.204 with SMTP id w70ls9079474ota.41.gmail; Sat, 04 Feb
 2017 09:27:39 -0800 (PST)
X-Received: by 10.157.52.34 with SMTP id v31mr200998otb.9.1486229259112;
        Sat, 04 Feb 2017 09:27:39 -0800 (PST)
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:30771
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/30771>

------=_Part_893_515332329.1486229258407
Content-Type: multipart/alternative; 
	boundary="----=_Part_894_198252994.1486229258407"

------=_Part_894_198252994.1486229258407
Content-Type: text/plain; charset=UTF-8

I've created a proposal draft (see attachment).

-- 
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/845d8ffe-13e2-4597-882c-0404ad582cef%40isocpp.org.

------=_Part_894_198252994.1486229258407
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I&#39;ve created a proposal draft (see attachment).<br></d=
iv>

<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/845d8ffe-13e2-4597-882c-0404ad582cef%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/845d8ffe-13e2-4597-882c-0404ad582cef=
%40isocpp.org</a>.<br />

------=_Part_894_198252994.1486229258407--

------=_Part_893_515332329.1486229258407
Content-Type: text/html; charset=US-ASCII; 
	name=safe_comparison_proposal.html
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=safe_comparison_proposal.html
X-Attachment-Id: f35ef8a6-6476-471b-9f53-cdaaf7f6376e
Content-ID: <f35ef8a6-6476-471b-9f53-cdaaf7f6376e>

<html>
	<head>
		<title>safe integral comparisons</title>
	</head>
	<body>
		<address>
			Document number: Dnnnn=yy-nnnn</br>
			Date: 2017-02-04</br>
			Project: safe integral comparisons</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 an 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 rappresent 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 <limits>
#include <type_traits>

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_893_515332329.1486229258407--

.
