Boost logo

Boost :

From: David Abrahams (abrahams_at_[hidden])
Date: 2000-09-29 18:31:42


While this technique doesn't allow users to graft on their own
specializations for various types, it seems like it will allow us to work
around the limitation in our own libraries when the types concerned are
pointers. That's exciting! Unfortunately, one of the most common needs for
partial specialization remains unaddressed, AFAICT: a method of
distinguishing reference types with certainty.

-Dave

----- Original Message -----
From: "Mat Marcus" <mmarcus_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Friday, September 29, 2000 6:03 PM
Subject: [boost] Simulating Partial Specialization

>
> Colleagues:
>
> Today much of the current C++ literature laments the lack of
> widespread compiler support for partial template specialization.
> There are some well known workarounds, but they tend to be of limited
> applicability. We are currently employing a "simulated partial
> specialization" technique that applies to a broader range of
> problems. In particular allows specialization of template classes for
> pointer types. One interesting application is to allow improved STL
> implementations on non-compliant compilers. The following code was
> tested on Microsoft Visual C++ 6 service pack 3. In this toy example
> we present a simple vector class which is specialized for pointer
> types. The template metaprogramming techniques used support
> simulation of other partial specialization features, e.g. holding one
> or more template parameters fixed, as well as a kind of poor man's
> typeof. We have enjoyed some success applying these techniques to a
> larger STL-style generic container library.
>
> Here is an outline of the idea. We make use of the IF template
> metafunction (or SWITCH if there is more than one specialization)
> and the sizeof operator.
>
> IF --- IF is actually a template struct based on a bool and two type
> parameters - IF<bool, IfType, ElseType>. It 'returns' the
> appropriate type via the RET typedef where RET stands for return.
>
> sizeof --- we recently learned of the flexibility of the sizeof
> operator.In particular sizeof can accept a function expression
> without evaluating the function. We declare (but do not define) a
> pair of discriminating functions to determine if a specialization
> applies. In the case of pointers we (essentially) use
>
> char IsPtr(const volatile void*);
> int IsPtr(...);
>
> We convert this pair of discriminating functions into a template
> metafunction ISPTR<T>. That is, ISPTR <T> returns true in the RET
> enum if and only if T is a pointer type. Finally this allows us to
> write IF<ISPTR<T>::RET, PointerSpecialized<T>,
> Unspecialized<T> >::RET to achieve simulated partial specialization
> where PointerSpecialized is the specialized version of the type and
> Unspecialized is the general case. By varying these discriminators we
> can specialize on other criteria.
>
> As stated above we can generalize this technique using the SWITCH
> metafunction and more than two discriminating functions. For example
> we might define a discriminating metafunction SPECIALIZER which
> returns an int rather than a bool. Than the simulated specialization
> would look like
>
> SWITCH<SPECIALIZER<T>,
> CASE<1, FIRST_SPECIALIZATION<T>,
> CASE<2, SECOND_SPECIALIZATION<T>,
> CASE<DEFAULT, GENERAL_CASE<T> >::RET
>
> Needless to say it is possible to discriminate on more than one
> template parameter.
>
> Hope you find this useful,
>
> Mat Marcus - mmarcus_at_[hidden]
> Jesse Jones - jejones_at_[hidden]
>
> References:
> Thanks to Krzysztof Czarnecki & Ulrich Eisenecker for the
> metaprogramming skills from the book Generative Programming. Thanks
> to Scott Meyers and Andrei Alexandrescu for the posts regarding the
> utility of the sizeof operator. Thanks to John R. Bandela for making
> us consider whether there might be some portable way to simulate
> partial specialization.
>
> License: The Adobe source code below is provided under the Adobe Open
> Source License 1.0. Please see file AdobeLicense.txt for licensing
> information.
>
>
>
>
> //##################################################################
> // File: PartialSpecialization.cpp
> // Authors: Mat Marcus and Jesse Jones
> // Copyright 2000 Adobe Systems Incorporated and others. All rights
reserved.
> // The original version of this source code may be found at
> http://opensource.adobe.com.
> // The contents of this file are subject to the Adobe Open Source
> // License Version 1.0.
>
> #include <iostream>
> #include <string>
> #include "metactrl.h" // General template meta-functions
> #include "is_ptr.h" // IsPtr template meta-function
>
>
> template <class T>
> struct SimpleVector {
> // Simple example vector class. We omit almost all implementation.
> friend std::ostream& operator<<(std::ostream& out, const
SimpleVector<T>&)
> {
> return out << "is a simple vector";
> }
> };
>
> template <class T>
> struct PtrVector {
> // Simple example vector of pointers class. We omit almost all
> implementation.
> friend std::ostream& operator<<(std::ostream& out, const
PtrVector<T>&)
> {
> return out << "is a pointer vector";
> }
>
>
> };
>
> template <class T>
> struct SELECT_VECTOR {
> // The SELECT_VECTOR meta-function exists simply to make
> // the following code more readable.
> typedef typename metactrl::IF<metactrl::ISPTR<T>::RET,
> PtrVector<T>,
> SimpleVector<T>
> >::RET Vector;
> };
>
> /* The heart of the matter. The meta-function metactrl::IF takes a boolean
> and returns the second type parameter if true else the third. This is
a
> useful tool in template metaprogramming (see metactrl.h for details).
> The meta-function metactrl::ISPTR makes use of the sizeof operator to
> convert a type into a bool indicating whether or not it is a pointer.
> See is_ptr.h for details.
> */
>
> template <class T>
> struct Vector : public SELECT_VECTOR<T>::Vector {
> // One way to achieve a general Vector class is to inherit from the
> // appropriate specialization. Clients can simply use Vector<T> and
> // we will specialize accordingly. However this inheritance based
> // wrapper approach has some limitations.
> };
>
>
>
>
> // We illustrate two approaches to simulated partial specialization
>
> int main(int argc, char* argv[])
> {
> // Example 1 using the inheritance based wrapper approach
> Vector<int> vi;
> std::cout << "Vector of int " << vi << std::endl;
> //Output: Vector of int is a simple vector
>
> Vector<int*> vip;
> std::cout << "Vector of int* " << vip << std::endl;
> //Output: Vector of int* is a pointer vector
>
>
> // Example 2 using the direct approach
> SELECT_VECTOR<std::string>::Vector ds;
> std::cout << "Vector of string " << ds << std::endl;
> //Output: Vector of string is a simple vector
>
> SELECT_VECTOR<std::string*>:: Vector dsp;
> std::cout << "Vector of string* " << dsp << std::endl;
> //Output: Vector of string* is a pointer vector
>
> return 0;
> }
>
>
> //##################################################################
>
> // File: is_ptr.h
> // Authors: Mat Marcus and Jesse Jones
> // Copyright 2000 Adobe Systems Incorporated and others. All rights
reserved.
> // The original version of this source code may be found at
> http://opensource.adobe.com.
> // The contents of this file are subject to the Adobe Open Source
> // License Version 1.0.
>
> namespace metactrl {
> namespace intimate {
> struct PointerShim {
> // Since the compiler only allows at most one non-trivial
> // implicit conversion we can make use of a shim class to
> // be sure that IsPtr below doesn't accept classes with
> // implicit pointer conversion operators
> PointerShim(const volatile void*); // no implementation
> };
>
> // These are the discriminating functions
> char IsPtr(PointerShim); // no implementation is required
> int IsPtr(...); // no implementation is required
> }
>
> template <class T>
> struct ISPTR {
> // This template meta function takes a type T
> // and returns true exactly when T is a pointer.
> // One can imagine meta-functions discriminating on
> // other criteria.
>
> enum { RET = (sizeof(intimate::IsPtr(*(T*)0)) == 1) };
> };
> }
>
> //##################################################################
>
> // File: metactrl.h
> // Authors: Krzysztof Czarnecki & Ulrich Eisenecker
> // We present only a small subset here
>
> /* The following functions come from chapter 10 of the indispensable book
> Generative Programming by Krzysztof Czarnecki & Ulrich Eisenecker
> (C) Copyright Krzysztof Czarnecki & Ulrich Eisenecker 1998-2000.
> Permission to copy, use, modify, sell and distribute this software is
> granted provided this copyright notice appears in all copies. In case of
> modification, the modified files should carry a notice stating that
> you changed the files.
> This software is provided "as is" without express or implied
> warranty, and with no claim as to its suitability for any purpose.
> */
> namespace metactrl
> {
>
> // IF<> // version for compilers without partial specialization
>
> namespace intimate
> {
> struct SelectThen
> { template<class Then, class Else>
> struct Result
> { typedef Then RET;
> };
> }; // end SelectThen
>
> struct SelectElse
> { template<class Then, class Else>
> struct Result
> { typedef Else RET;
> };
> }; // end SelectElse
>
> template<bool Condition>
> struct Selector
> { typedef SelectThen RET;
> }; // end Selector
>
> template<>
> struct Selector<false>
> { typedef SelectElse RET;
> }; // end Selector<false>
> } // end namespace intimate
>
> template<bool Condition, class Then, class Else>
> struct IF
> { typedef intimate::Selector<Condition>::RET select;
> typedef select::Result<Then,Else>::RET RET;
> }; // IF
> } // end namespace metactrl
>
>
> // CASE<>, SWITCH<> // version for compilers without partial
specialization
>
> const int DEFAULT = -32767;
>
> namespace intimate
> {
> const int NilValue = -32768;
>
> struct NilCase
> { enum {tag = NilValue};
> typedef NilCase RET;
> }; // NilCase
> } // end namespace intimate;
>
> template <int Tag,class Statement,class Next = intimate::NilCase>
> struct CASE
> { enum {tag = Tag};
> typedef Statement statement;
> typedef Next next;
> }; // CASE
>
> template <int Tag,class aCase>
> struct SWITCH
> { typedef aCase::next nextCase;
> enum { tag = aCase::tag, // VC++ 5.0 doesn't operate directly on
> aCase::value in IF<>
> nextTag = nextCase::tag,// Thus we need a little cheat
> found = (tag == Tag || tag == DEFAULT)
> };
> typedef IF<(nextTag == intimate::NilValue),
> intimate::NilCase,
> SWITCH<Tag,nextCase> >
> ::RET nextSwitch;
> typedef IF<(found != 0),
> aCase::statement,
> nextSwitch::RET>
> ::RET RET;
> }; // SWITCH
>
> //#########################################
> //file: AdobeLicense.txt
>
> Notice to User: Adobe Systems Incorporated ("Adobe") is providing the
> source code in these documents for use under the terms of this Adobe
> Open Source License Agreement ("Agreement"). Any use, reproduction,
> modification, or distribution of the source code, resulting object
> code, or related documentation on this site, or any derivatives
> thereof (collectively, the "Software") constitutes your acceptance of
> this Agreement. Adobe reserves the right to make changes to this
> Agreement from time to time at its sole discretion. The version of
> this Agreement posted on the date you download the Software will
> apply to that version of the Software.
> 1. License Grant
> Subject to the terms of this Agreement, Adobe grants you a
> non-exclusive, worldwide, royalty free license to use, reproduce,
> prepare derivative works, publicly display, publicly perform,
> distribute, and sublicense the Software for any purpose, provided the
> copyright notice below, appears in a conspicuous location within the
> source code of the distributed Software and this license is
> distributed with the version of the Software you distribute in the
> supporting documentation.
> Copyright (Date Here) Adobe Systems Incorporated and others.
> All rights reserved.
> The original version of this source code may be found at
> http://opensource.adobe.com.
>
> If you choose to distribute the Software in a commercial product, you
> do so with the understanding that you agree to defend, indemnify, and
> hold harmless Adobe against any losses, damages, and costs, arising
> from the claims, lawsuits, and other legal actions, arising out of
> such distribution. You may distribute the Software in object code
> form under your own license, provided that your license agreement:
> (a) complies with the terms and conditions of this license agreement;
> (b) effectively disclaims all warranties and conditions, express
> or implied, on behalf of Adobe;
> (c) effectively excludes all liability for damages, on behalf of Adobe;
> (d) states that any provisions that differ from this Agreement
> are offered by you alone and not Adobe; and
> (e) states that the Software covered by this Agreement is
> available from you or Adobe and informs licenses how to obtain it in
> a reasonable manner on or through a medium customarily used for
> software exchange.
> 2. Disclaimer of Warranty
> ADOBE LICENSES THE SOFTWARE TO YOU ONLY ON AN "AS IS" BASIS WITHOUT
> WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
> INCLUDING WITHOUT LIMITATION ANY WARRANTIES OR CONDITIONS OF TITLE,
> NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
> PURPOSE. ADOBE MAKES NO WARRANTY THAT THE SOFTWARE WILL BE
> ERROR-FREE. Each user of the Software is solely responsible for
> determining the appropriateness of using and distributing the
> Software and assumes all risks associated with its exercise of rights
> under this Agreement, including but not limited to the risks and
> costs of program errors, compliance with applicable laws, damage to
> or loss of data, programs, or equipment, and unavailability or
> interruption of operations. Use of the Software is done so with the
> understanding that Adobe will not provide you with any technical or
> customer support or maintenance. Some states or jurisdictions do not
> allow the exclusion of implied warranties or limitations on how long
> an implied warranty may last, so the above limitations may not apply
> to you. To the extent permissible, any implied warranties are limited
> to ninety (90) days.
> 3. Limitation of Liability
> ADOBE SHALL NOT BE LIABLE FOR LOSS OR DAMAGE ARISING OUT OF THIS
> AGREEMENT OR FROM THE USE OF THE SOFTWARE. IN NO EVENT WILL ADOBE BE
> LIABLE TO YOU OR ANY THIRD PARTY FOR ANY DIRECT, INDIRECT,
> CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES INCLUDING LOST PROFITS,
> LOST SAVINGS, COSTS, FEES, OR EXPENSES OF ANY KIND ARISING OUT OF ANY
> PROVISION OF THIS AGREEMENT OR THE USE OR THE INABILITY TO USE THE
> SOFTWARE, HOWEVER CAUSED AND UNDER ANY THEORY OF LIABILITY, WHETHER
> IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE OR
> OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
> 4. Trademark Usage
> Adobe is a trademark or registered trademark of Adobe Systems
> Incorporated in the United States and/or other countries. Neither the
> Adobe name nor the Adobe logo may be used to endorse or promote
> products derived from this site.
> 5. Termination
> User rights shall terminate under this Agreement if the user fails to
> comply with any of the material terms or conditions of this Agreement
> and does not cure such failure in a reasonable period of time after
> becoming aware of such noncompliance. If all user's rights under this
> Agreement terminate, user agrees to cease use and distribution of the
> Software as soon as reasonably practicable.
> 6. Governing Law and Jurisdiction
> This Agreement is governed by the statutes and laws of the State of
> California, without regard to the conflicts of law principles
> thereof. If any part of this Agreement is found void and
> unenforceable, it will not affect the validity of the balance of the
> Agreement, which shall remain valid and enforceable according to its
> terms. This is the entire agreement between Adobe and you relating to
> the Software.
>
>
>


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk