[mpl] need help with 'extended template parameter matching'

Dear All, I'm trying to write a metafunction rebind which, when fed a specialization T<P1,...,Pn> of an n-ary template T, returns T<mpl::_, ...., mpl::_>. This is straightforward if default template arguments are not considered when matching template template parameters. (See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#150.) E.g., template<typename T> struct rebind { typedef T type; } template<template<typename> class T, typename P> struct rebind< T<P> > { typedef T<mpl::_> type; }; template<template<typename, typename> class T, typename P1, typename P2> struct rebind< T<P1, P2> > { typedef T<mpl::_, mpl::_> type; }; etc. On GCC 3.4.1 (and I assume earlier versions too) this leads to ambiguity errors. To workaround this problem, I've resorted to using enable_if and mpl::aux::template_arity, e.g., template<typename T, typename Enabler = void> struct rebind { typedef T type; } template<template<typename> class T, typename P> struct rebind< T<P>, typename enable_if< mpl::equal_to< typename mpl::aux::template_arity< T<P> >::type, mpl::int_<1> > >::type > { typedef T<mpl::_> type; }; I have two questions: 1. is my analysis correct? 2. is there a better solution? Best Regards, Jonathan

Jonathan Turkanis wrote:
Dear All,
I'm trying to write a metafunction rebind which, when fed a specialization T<P1,...,Pn> of an n-ary template T, returns T<mpl::_, ...., mpl::_>. This is straightforward if default template arguments are not considered when matching template template parameters. (See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#150.) E.g.,
[snip code]
I have two questions:
1. is my analysis correct?
I think so.
2. is there a better solution?
I don't know if it's better, but you can get rid of the SFINAE by doing something like: struct _ {}; template<class T, int N = 3> struct rebind : rebind<T, N - 1> {}; template<class T> struct rebind<T, 0> { typedef T type; }; template<template<class> class T, class P1> struct rebind<T<P1>, 1> { typedef T<_> type; }; template<template<class, class> class T, class P1, class P2> struct rebind<T<P1, P2>, 2> { typedef T<_, _> type; }; template< template<class, class, class> class T , class P1, class P2, class P3
struct rebind<T<P1, P2, P3>, 3> { typedef T<_, _, _> type; }; Or you could just use template_arity to pass the arity to the specialized template, instead of recursively trying every arity. I suspect template_arity has to do something equivalent to this though, so maybe this saves a few instantiations. HTH, -- Daniel Wallin

"Daniel Wallin" <dalwan01@student.umu.se> wrote in message:
I don't know if it's better, but you can get rid of the SFINAE by doing something like:
struct _ {};
template<class T, int N = 3> struct rebind : rebind<T, N - 1> {};
template<class T> struct rebind<T, 0> { typedef T type; };
template<template<class> class T, class P1> struct rebind<T<P1>, 1> { typedef T<_> type; };
template<template<class, class> class T, class P1, class P2> struct rebind<T<P1, P2>, 2> { typedef T<_, _> type; };
template< template<class, class, class> class T , class P1, class P2, class P3
struct rebind<T<P1, P2, P3>, 3> { typedef T<_, _, _> type; };
Or you could just use template_arity to pass the arity to the specialized template, instead of recursively trying every arity. I suspect template_arity has to do something equivalent to this though, so maybe this saves a few instantiations.
Thanks for the suggestions. I was hoping there might be something radically simpler. I think I"m happy to stick with enable_if and template arity (on platforms which require it), since it states the intent very clearly. It can also be encapsulated better than the example I posted, e.g., enable_by_arity< T<P>, 1 > ... .
HTH, -- Daniel Wallin
Jonathan
participants (2)
-
Daniel Wallin
-
Jonathan Turkanis