Boost logo

Boost :

From: Vesa Karvonen (vesa.karvonen_at_[hidden])
Date: 2001-06-27 05:58:42


From: "Michael Stevens" <michael_at_[hidden]>
> I really want to use boost Quaternions an would like to produce VC++6.0
> (SP5) compatible code. To this end I've been looking at how much
> template template parameters workaround help. To this end I put together
> a very short piece of test code. The code has two sections: the first
> uses template template parameters, the second is the equivilent
> transformed into member templates.
>
> Both compile well under gcc2.95.2
> VC however has serious problems even with the transformed code. In
> particular it is unable to insantiate the template: see // critical
> line.
> Interestingly if the struct PP is rename struct P (this name is
> irrelavent) then an internal compiler error is produced!
>
> All bad news. It doesn't look like it is possible to work around VC++6.0
> problems in this case.

I think that you might want to take a look at the MPL library in the Files
section. It contains a workaround for the "dependent template" MSVC bug.
(Search for "DEPENDENT" in the MPL code.)

The following is a snippet from my template metaprogramming library. The
snippet was derived from the workaround used by MPL.

Notes:
- It assumes that the member template name is "code" (following the standard
set in Czarnecki & Eisenecker. I also use "apply" for static member functions,
and I'm afraid of possible collisions.)
- It uses the PREPROCESSOR library (see Files section).
- You can extend the following workaround for other template names simply by
replacing the "code" with some other name.

The workaround is used like this:

    struct X
    { template
      <class P
>
      struct code
      { typedef int type;
      }
    };

    template<class T>
    struct Y
    { typedef typename dependent_code<T>::template code<long>
        type;
    };

    template<class T>
    struct Z
    { typedef typename dependent_code<T>::template code<long>::type
        type;
    };

I noticed that the above workaround does not always work. Therefore I
developed two additional helper templates:

    call_code_##N<func, p0, p1, ..., pn-1>
    get_code_##N<func, p0, p1, ..., pn-1>

They are then used like this:

    template<class T>
    struct Y
    { typedef typename get_code_1<T,long>::type
        type;
    };

    template<class T>
    struct Z
    { typedef typename call_code_1<T,long>::type
        type;
    };

So far I have not had major problems with the above helper templates. I think
that they can even be considered improvements over the standard C++
typename::template syntax:

    template<class T>
    struct Y
    { typedef typename T::template code<long>
        type;
    };

    template<class T>
    struct Z
    { typedef typename T::template code<long>::type
        type;
    };

However, I'm not satisfied with my implementation of the get_code_##N<> and
call_code_##N<>, because I think that it is possible to remove the "_##N"
suffix from them. I think that the same technique that could be used for
removing the _##N can also be used for implementing currying and arbitrary
parameter binding. I'll post my implementation of get_code<> and call_code<>
templates and possibly bind_code<fun,i,pi> in the future unless someone else
finds time to implement them sooner.

### BEGIN CODE SNIPPET ###

// Copyright (C) 2001 by Vesa Karvonen. Permission to copy, use, modify,
// sell and distribute this software is granted provided this copyright
// notice appears in all copies. This software is provided "as is" without
// express or implied warranty, and with no claim as to its suitability for
// any purpose.
//
// This msvc dependent member workaround derives from work by:
//
// Copyright (c) 2000-01
// Aleksey Gurtovoy
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appears in all copies and
// that both the copyright notice and this permission notice appear in
// supporting documentation. No representations are made about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.

// This is a workaround for a specific MSVC bug. Apparently MSVC is too
// eager in checking the validity of template code. This workaround cheats
// the compiler to accept the (valid) code.

#ifdef BOOST_MSVC

namespace detail
{ template
  < class T
>
  struct never_true
  { enum
    { value = false
    };
  };

  template
  < class func
>
  struct dependent_code_helper
  { template<bool>
    struct _ : func
    {
    };

    template<>
    struct _<true>
    { template
      < BOOST_PREPROCESSOR_ENUM_PARAMS_WITH_A_DEFAULT
        ( BOOST_TMPL_CODE_PARAMS_MAX
        , class p
        , _<true>
        )
>
      struct code;
    };
  };
}

template
< class func
>
struct dependent_code
  : detail::dependent_code_helper<func>
      ::template _<detail::never_true<func>::value>
{
};

#else

template
< class code
>
struct dependendent_code
  : code
{
};

#endif

// get_code_##N

#define BOOST_PREPROCESSOR_DEF(N,A,B)\
    template\
    < class fun\
    , BOOST_PREPROCESSOR_ENUM_PARAMS\
      ( BOOST_PREPROCESSOR_INC(N)\
      , class p\
      )\
>\
    struct BOOST_PREPROCESSOR_CAT(get_code_,BOOST_PREPROCESSOR_INC(N))\
    { typedef typename\
        dependent_code<fun>\
          ::template code\
          < BOOST_PREPROCESSOR_ENUM_PARAMS\
            ( BOOST_PREPROCESSOR_INC(N)\
            , p\
            )\
> type;\
    };

    BOOST_PREPROCESSOR_2ND_REPEAT
    ( BOOST_TMPL_CODE_PARAMS_MAX
    , BOOST_PREPROCESSOR_DEF
    , A
    , B
    )
#undef BOOST_PREPROCESSOR_DEF

// call_code_##N

#define BOOST_PREPROCESSOR_DEF(N,A,B)\
    template\
    < class fun\
    , BOOST_PREPROCESSOR_ENUM_PARAMS\
      ( BOOST_PREPROCESSOR_INC(N)\
      , class p\
      )\
>\
    struct BOOST_PREPROCESSOR_CAT(call_code_,BOOST_PREPROCESSOR_INC(N))\
      : BOOST_PREPROCESSOR_CAT(get_code_,BOOST_PREPROCESSOR_INC(N))\
        < fun\
        , BOOST_PREPROCESSOR_ENUM_PARAMS\
          ( BOOST_PREPROCESSOR_INC(N)\
          , p\
          )\
>::type\
    {\
    };

    BOOST_PREPROCESSOR_2ND_REPEAT
    ( BOOST_TMPL_CODE_PARAMS_MAX
    , BOOST_PREPROCESSOR_DEF
    , A
    , B
    )
#undef BOOST_PREPROCESSOR_DEF

### END CODE SNIPPET ###


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