From stdcxx-dev-return-2480-apmail-incubator-stdcxx-dev-archive=incubator.apache.org@incubator.apache.org Sat Dec 23 23:22:55 2006 Return-Path: Delivered-To: apmail-incubator-stdcxx-dev-archive@www.apache.org Received: (qmail 93215 invoked from network); 23 Dec 2006 23:22:55 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 23 Dec 2006 23:22:55 -0000 Received: (qmail 69253 invoked by uid 500); 23 Dec 2006 23:23:02 -0000 Delivered-To: apmail-incubator-stdcxx-dev-archive@incubator.apache.org Received: (qmail 69243 invoked by uid 500); 23 Dec 2006 23:23:02 -0000 Mailing-List: contact stdcxx-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: stdcxx-dev@incubator.apache.org Delivered-To: mailing list stdcxx-dev@incubator.apache.org Received: (qmail 69230 invoked by uid 99); 23 Dec 2006 23:23:02 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 23 Dec 2006 15:23:02 -0800 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received-SPF: pass (herse.apache.org: local policy) Received: from [208.30.140.160] (HELO moroha.quovadx.com) (208.30.140.160) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 23 Dec 2006 15:22:52 -0800 Received: from qxvcexch01.ad.quovadx.com (qxvcexch01.ad.quovadx.com [192.168.170.59]) by moroha.quovadx.com (8.13.6/8.13.6) with ESMTP id kBNNLoYg021696 for ; Sat, 23 Dec 2006 23:21:50 GMT Received: from [10.70.3.113] ([10.70.3.113]) by qxvcexch01.ad.quovadx.com with Microsoft SMTPSVC(6.0.3790.1830); Sat, 23 Dec 2006 16:22:04 -0700 Message-ID: <458DBA4F.8000408@roguewave.com> Date: Sat, 23 Dec 2006 16:22:55 -0700 From: Martin Sebor Organization: Rogue Wave Software User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.13) Gecko/20060417 X-Accept-Language: en-us, en MIME-Version: 1.0 To: stdcxx-dev@incubator.apache.org Subject: Re: type_traits is_integral implementation References: In-Reply-To: Content-Type: multipart/mixed; boundary="------------010906060609010503020806" X-OriginalArrivalTime: 23 Dec 2006 23:22:04.0922 (UTC) FILETIME=[2854A5A0:01C726E9] X-Virus-Checked: Checked by ClamAV on apache.org --------------010906060609010503020806 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Scott Zhong wrote: > I try to implement type_traits using partial specialization as follows: > > template struct __remove_s { typedef T type; }; > template struct __remove_s { typedef T type; }; > template struct __remove_s { typedef T type; }; > template struct __remove_s { typedef T type; }; > template struct __remove_s { typedef T type; }; > > template struct is_integral: > __is_same __remove_cv::type>::type, int> { }; > > But signed is actually a type and T is already a type, and signed int is > a compound type. signed int is a fundamental type (3.9.1). It's also an arithmetic type, but it's not a compound type (3.9.2). Precise terminology is important when discussing traits :) Unlike constness or volatility, signedness is a property that's inherent to integer types. It's not something that can be removed or added. The "signed" in, say, "signed long," is a part of the name of the type, not just some attribute. Ditto for signed short or signed int. Think of long, short, and int as aliases for the verbose forms of their names. > When compiling the above code in MSVC 8.0, it would > give an error that states "too many template arguments". That's a poor error message. Gcc says: error: long, short, signed or unsigned invalid for 'type name' error: partial specialization 'S' does not specialize any template arguments > I went ahead > and read the book you had pointed to me, the implementation in there is > using 3 enum? with a 3rd struct containing index_of template that would > search though the enum with return value of greater than 0 if found, 0 > if not found. I decided to implement it a different way as follows: [...] > Not really sure the internal workings of a template, does it treat each > specialization as an enum? My implementation does generate 5 template > instantiation whenever is_integral is called, would that adversely > affect performance? Please let me know if there is a better > implementation. I would suggest you start by defining what an integer type is. Writing down the definition will be helpful in breaking up the implementation of the trait into smaller, more manageable bits. Here's how section 3.9 of the working draft of the C++ standard defines an integral type: A C++ integral type is one of: bool, char, wchar_t, signed integer type, or unsigned integer type A signed integer type is one of: standard signed integer type, or extended signed integer type An unsigned integer type is one of: standard unsigned integer type or extended unsigned integer type A standard signed/unsigned integer type is one of: short, int, long, long long unsigned short, unsigned, unsigned long, and unsigned long long An extended signed/unsigned integer type is one of: a set of implementation-defined types It should be relatively easy to model an implementation of the trait based on the definition. But before you start, since you already know that the trait (like many others) is required to yield the same result when specialized on a cv-qualified type as when specialized on a plain type, you might want to create some simple helper traits that will let you remove any cv-qualifications from types (remove_const, remove_volatile, and remove_cv), or determine whether two types are the same (is_same). These helper traits are also a required part of the type traits interface (see 20.4.7) so by coding them you'll be ahead of the game :) Attached is my attempt at defining the helpers and the trait. Take a look at it to see if it makes sense to you. As you can already see there are a number of ways of implementing these critters. I would encourage you to experiment with different approaches to see which one you like best and how long each takes the compile with which compiler. The goal should be to come up with an elegant, compact implementation that's fast to compile and that generates the least number of specializations of implementation classes (deep template recursion is the enemy of compile time efficiency). Martin --------------010906060609010503020806 Content-Type: text/plain; name="t.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="t.cpp" template struct integral_constant { typedef T value_type; static const value_type value = v; typedef integral_constant type; }; template const typename integral_constant::value_type integral_constant:: value; typedef integral_constant true_type; typedef integral_constant false_type; template struct remove_const { typedef T type; }; template struct remove_const { typedef T type; }; template struct remove_volatile { typedef T type; }; template struct remove_volatile { typedef T type; }; template struct remove_cv: remove_const::type> { }; template struct is_same: false_type { }; template struct is_same: true_type { }; // is T a standard signed/unsigned integer type? template struct __is_std_signed: false_type { }; template struct __is_std_unsigned: false_type { }; // __is_std_signed specializations for each standard signed // integer type (T must not be cv-qualified) template <> struct __is_std_signed: true_type { }; template <> struct __is_std_signed: true_type { }; template <> struct __is_std_signed: true_type { }; template <> struct __is_std_signed: true_type { }; template <> struct __is_std_signed: true_type { }; // __is_std_unsigned specializations for each standard unsigned // integer type (T must not be cv-qualified) template <> struct __is_std_signed: true_type { }; template <> struct __is_std_signed: true_type { }; template <> struct __is_std_signed: true_type { }; template <> struct __is_std_signed: true_type { }; template <> struct __is_std_signed: true_type { }; // __is_ext_signed and __is_ext_unsigned traits for implementation // defined extended signed and extended unsigned integer types template struct __is_ext_signed: false_type { }; template struct __is_ext_unsigned: false_type { }; template struct is_signed: integral_constant::type>::value || __is_ext_signed::type>::value> { }; template struct is_unsigned: integral_constant::type>::value || __is_ext_unsigned::type>::value> { }; template struct is_integral: integral_constant< bool, is_signed::value || is_unsigned::value || is_same::type, bool>::value || is_same::type, char>::value || is_same::type, wchar_t>::value> { }; #include template void test () { // verify that is_integral is publicly (directly or otherwise) // derived from integral_constant and that the base // has a static const data member of type bool named value with // the expected value (and if the same member exists in the // derived class it has the same value as well) #define TEST(T) \ do { \ const is_integral trait = is_integral(); \ typedef integral_constant Base; \ const Base &base = trait; \ const bool &base_result = Base::value; \ const bool &derived_result = is_integral::value; \ assert (Expect == base_result); \ assert (base_result == derived_result); \ } while (0) TEST (T); TEST (const T); TEST (volatile T); TEST (const volatile T); } typedef int Array []; struct Incomplete; enum Enumeration { }; typedef void Function (); typedef void (*FunctionPointer)(); typedef int Incomplete::*MemberPointer; typedef void (Incomplete::*MemberFunctionPointer)(); int main () { // exercise signed intergral types test(); test(); test(); test(); test(); // exercise unsigned intergral types test(); test(); test(); test(); test(); // exercise bool, char, and wchar_t test(); test(); test(); // references to integral types are not themselves integral types test(); test(); test(); test(); test(); test(); test(); test(); // exercise floating point types test(); test(); test(); // exercise other types test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); test(); } --------------010906060609010503020806--