|
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