⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readme.txt

📁 《C++设计新思维》中的Loki源代码。其中把template用到了极致。
💻 TXT
📖 第 1 页 / 共 2 页
字号:
Loki VC 6.0 Port or how to produce C1001 - Internal Compiler Errors
-------------------------------------------------------------------
Version: 0.5e

Introduction/Compatibility:
---------------------------
This is a partial MSVC 6.0 Sp5 compatible port of Andrei Alexandrescu's excellent Loki Library.
Because I could not retain the originial interface in all places, this port is not
compatible to the original library and therefore code using this port *cannot* generally be
used together with the original lib.
This is, of course, a great pity.
So if you know of a complete and full interface-compatible VC 6.0
port or if you know how to improve this port, please let me know.

Contact:
--------
For any suggestions, bug reports, comments and questions please email me to
Hume@c-plusplus.de

Using this port:
----------------
To use this port, simply extract the files from the archive, give your compiler access to
their path, and include them appropriately in your code via #include.

If you use the small object allocator directly or indirectly (through the Functor class)
you must add SmallObj.cpp to your project/makefile.

If you use Singletons with longevity you must add Singleton.cpp to your project/makefile.

Fixes:
------
    Mar 18, 2004:
    -------------
    	* In SmartPtr.h: Added operator=-workaround for pointer-assignment
    	* In Functor.h:  Changed value parameter to reference parameter
    					 in FunctorBase and FunctorVoidBase Ctors.
    Mar 21, 2003:
    -------------
        * In MultiMethods.h: Added a new explicit template argument specification (ETAS)-workaround
        for FnDispatcher::Add which is more compliant with other
        ETAS-workarounds used in this port.

    Mar 20, 2003:
    -------------
        * In MultiMethods.h: Fixed bugs in FnDispatcher and FunctorDispatcher.
        Fixing FnDispatcher led to an Interface change (see section "Interface changes").

	Mar 08, 2003:
    -------------
        * In HierarchyGenerators.h: implemented transparent workaround for
        'explicit template argument specification for nonmeber functions'-bug.
        The Field-Functions can now be called as in the original lib.

    Mar 06, 2003:
    -------------
        * In SmartPointer.h: Added helper-macros for convenient specialization
        of std::less for Smart-Pointers.

        * I found a way to use void as a default value for template parameters.
        Therefore I changed MultiMethods.h and Visitor.h accordingly.


    Feb 2003:
	---------
		* created new versions of Functor.h, Visitor.h and MultiMethods.h that
		now can handle void return types transparently.

		* ported SmartPtr's Ownership-Policy RefCountedMT

		* Added isFunctionPointer to TypeTraits.

		* Replaced all pointer-type dummy-parameters needed as a workaround
		for VC's 'explicit template argument specification'-bug with Typ2Type-dummy
		parameters.

		* fixed the problems with BindFirst (Functor.h) that led to
		C1001-Internal compiler errors.

		* fixed numerous other bugs.


    Jan 30, 2003:
    -------------
        * In TypeTraits.h: Fixed bugs in TypeTraits' scalar and array detection.
        const and volatile detection is now based on techniques from boost's type traits
        (see http://www.boost.org/libs/type_traits/)
        Added Enum- and pointer-to-member-function-detection code.
        Thanks to M. Yamada.


    Jan 12, 2003:
    -------------
    	* changed the signature of SmallObject's op new. Now it
    	matches the corresponding op delete.
		Thanks to M.Yamada for the hint and the solution.

    Dec 08, 2002:
    -------------
        * In HierarchyGenerators.h: Sergey Khachatrian reported a bug
        in GenScatterHierarchy when used with a typelist containing
        equal types (e.g. GenScatterHierarchy<TYPELIST_2(int, int), UnitWrapper>
        resp. Tuple<TYPELIST_2(int, int)>)
        Fixing the bug I found another MSVC6-Problem in the Field-function.
        The workaround for this problems results in an interface change.

        please refer to the section "Interface changes" below for further information.

    Dec 03, 2002
    -------------
        * In MSVC6Helpers.h: The original version failed to qualify some types from the
        Private-Namespace.
        Thanks to Adi Shavit for pointing that out

        * In Threads.h: Changed wrong ctor/dtor names in ObjectLevelLockable.
        Thanks to Adi Shavit for pointing that out

    Nov 19, 2002:
    -------------
        * In SmartPtr.h: Changed template ctors. See Notes.

Notes:
------
The original Loki Lib uses some pretty advanced (resp. new) C++ features like:

A. partial template specialization.
B. template template parameters.
C. explicit template argument specification for member- and nonmeber functions.
D. covariant return types.
E. Template parameters with default type void
F. return statements with an expression of type cv void in functions with a return type of cv void.

Unfortunately the MSVC 6.0 supports neither of them.

    A. I used various techniques to simulate partial template specialization. In some cases
    these techniques allowed me to retain the original interfaces but often that was not
    possible (or better: i did not find a proper solution). In any case it led
    to increasing code complexity :-)

    B. One way to simulate template template parameters is to replace the template class with
    a normal class containing a nested template class. You then move the original functionality
    to the nested class.
    The problem with this approach is MSVC's 'dependent template typedef bug'.
    MSVC 6.0 does not allow something like this:

    [code]
    template <class APolicy, class T>
    struct Foo
    {
        // error C2903: 'In' : symbol is neither a class template nor a function template
        typedef typename APolicy::template In<T> type;
    };
    [/code]

    To make a long story short, I finally decided to use boost::mpl's apply-technique to
    simulate template template parameters. This approach works fine with MSVC 6.0. But be warned,
    this technique uses not valid C++.
    Of course, replacing template template parameters always results in some interface changes.

    C. I added dummy-Parameters to (Member-)Functions that depend on explicit template
    argument specification. These dummy-Parameters help the compiler in deducing the template
    parameters that otherwise need to be explicitly specified.
    Example:
    [code]
    struct Foo
    {
        template <class T>
        T Func();
    };
    [/code]
    becomes
    [code]
    struct Foo
    {
        template <class T>
        T Func(Type2Type<T>);
    };
    [/code]
    in this port.

    Update:
    -------
    The MSVC 6.0 sometimes does not overload normal functions depending
    on explicit argument specification correctly (see: Microsoft KB Article - 240871)
    The following code demonstrates the problem:
    [code]
    template <unsigned i, class T>
    void BugDemonstration(T p)
    {
	    printf("BugDemonstration called with i = %d\n", i);
    }

    int main()
    {
        GenScatterHierarchy<TYPELIST_3(int, int, int), TestUnitWrapper> Bla;
	    // will always print: "BugDemonstration called with i = 2";
	    BugDemonstration<0>(Bla);
	    BugDemonstration<1>(Bla);
	    BugDemonstration<2>(Bla);
    }
    [/code]

    Fortunately there is a transparent workaround for this problem. Simply add
    a dummy-parameter with a proper default value:
    [code]
    template <unsigned i, class T>
    void BugDemonstration(T p, Int2Type<i>* = (Int2Type<i>*)0)
    {
	    printf("BugDemonstration called with i = %d\n", i);
    }

    int main()
    {
        GenScatterHierarchy<TYPELIST_3(int, int, int), TestUnitWrapper> Bla;
	    // will now work correctly
	    BugDemonstration<0>(Bla);
	    BugDemonstration<1>(Bla);
	    BugDemonstration<2>(Bla);
    }
    [/code]

    Unfortunately adding dummy-parameters does not always work.
    For example for one of FnDispatcher's Add-member-functions you have to explicitly
    specify two type- and one non-type parameter.
    [code]
    template </*...*/typename ResultType/*...*/>
    class FnDispatcher
    {
    public:
	    //...
	    template <class SomeLhs, class SomeRhs,
		    ResultType (*callback)(SomeLhs&, SomeRhs&)>
	    void Add(){/*...*/}
    };
    //...
    FnDispatcher<Shape> dis;
    dis.Add<Poly, Poly, &AFunc>();
    [/code]
    Using dummy-parameters as workaround FnDispatcher::Add would become something
    like this:
    [code]
    template<class S1, class S2, class R, R (*)(S1&,S2&)>
    struct Helper {};

    template </*...*/typename ResultType/*...*/>
    class FnDispatcher
    {
    public:
	    //...
	    template <class SomeLhs, class SomeRhs,
		    ResultType (*callback)(SomeLhs&, SomeRhs&)>
	    void Add(Helper<SomeLhs, SomeRhs, ResultType, callback>)
	    {}
    };
    //...
    FnDispatcher<void> f;
	f.Add(Helper<Rectangle, Rectangle, void, &Func>());
    [/code]
    This compiles fine, but alas Add never gets called. I don't know what happens,
    I only know that the MSVC 6.0 won't generate code for a function call.

    In situations like that, instead of dummy-Parameters I used nested template-classes
    with overloaded function-operator as a workaround.
    [code]
    template </*...*/typename ResultType/*...*/>
    class FnDispatcher
    {
    public:
	    // the member-function Add becomes a member-template-class
	    // with overloaded function operator.
	    template <class SomeLhs, class SomeRhs,
		    ResultType (*callback)(SomeLhs&, SomeRhs&)>
	    struct AddI
	    {
		    void operator()(FnDispatcher<ResultType>& o)  {/*...*/}
	    };
    };
    //...
    FnDispatcher<void> f;
	FnDispatcher<void>::AddI<Rectangle, Rectangle, &Func>()(f);
    [/code]

    If you know of a better workaround, please let me know.

    Update:
    -------
    The problem in the example above is Add's nontype-function-pointer-Parameter.
    If one changes this parameter to a type-parameter the problem vanishes.
    The example above then becomes:
    [code]
    template </*...*/typename ResultType/*...*/>
    class FnDispatcher
    {
    public:
	    // Etas stands for explicit template argument specification.
        // Do whatever you need to do with callback in this class.
        template <class SomeLhs, class SomeRhs,
			ResultType (*callback)(SomeLhs&, SomeRhs&), bool symmetric = false>
		struct Etas
		{/*...*/};

		// EtasType has to be a template parameter. If one tries to use
		// a parameter of type Etas the MSVC 6.0 won't generate correct
		// code.
		template <class EtasType>
        void Add(EtasType EtasObj)
        {/*...*/}
    };
    //...
    typedef FnDispatcher<void> DisType;
    DisType f;
	f.Add(DisType::Etas<Rectangle, Rectangle, &Func>());
    [/code]

    The port provides both workarounds but the use of the second should be preferred,
    because it betters fits to the rest of the port's workarounds.

    D. Virtual functions that use covariant return types (e.g. return a pointer to Derived)
    in the original library were changed so that they have exactly the
    same return type as the original virtual function (e.g. return a pointer to Base).

    E. The MSVC 6.0 does not allow code like this:
    [code]
    // error C2182: '__formal' illegal use of type 'void'
    template <class T, class R = void>
    struct Blub {};
    [/code]

    Interestingly enough you can have void as default type by simply using another
    level of indirection:
    [code]
    struct VoidWrap
    {
	    typedef void type;
    };

    template <class T, class R = VoidWrap::type>
    struct Blub
    {};
    [/code]

    F. To workaround void returns I did the following:
    From every original class I moved those functions that potentially
	produce void returns to new classes. One for the general case and
	one for the void case.
	In the class for the general case I implemented the functions in the original way.
	In the class for the void case I removed the return statements and therefore the
	potential void return.
	Depending on the return type, the original class inherits from the
	corresponding new class and thus gets the proper implementation of
	the previously removed functions.

	For example:
	[code]
	template <class R> struct Foo

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -