Boost logo

Boost :

From: David Abrahams (david.abrahams_at_[hidden])
Date: 2002-02-19 17:48:29


----- Original Message -----
From: "brianjparker" <brianjparker_at_[hidden]>

> --- In boost_at_y..., Carl Daniel <cpdaniel_at_p...> wrote:
> > I'd like to see the rule for template template argument
> compatibility relaxed (e.g. such that std::vector<T,A=allocator>
> > and myclass<T> would both be compatible with a template template
> parameter declared as template <class>). The current
> > rule appears to have been adopted to better meet with users
> expectations (as compared to function pointer
> > compatibility). The not-infrequent threads on c.l.c++.m about this
> subject suggest that it did just the opposite:
> > institutionalized behavior which is counter to expectations and
> unnecessarily limiting.
>
> I totally agree with this; in fact I would consider this change to
> more of a bug fix than a language extension. The main negative effect
> of the current rule is that it prevents future library classes from
> adding additional template arguments with defaults whilst still
> remaining backwardly compatible.

FWIW, both gcc and Borland "work" the way you'd like, and that bug cripples
meta-lambda expressions in MPL on those compilers. Before you buy into this
change you should consider this example Aleksey sent me today:

-------

    template< template<typename> class F > struct my {};
    template<typename T, typename U = T> struct her {};

    int main()
    {
        sizeof(my<her>); // should not compile, but ok with GCC/Borland
        return 0;
    }

BTW, it's kind of ironic - compile-time lambda facility allows you to
workaround this often-cited inflexibility of template template parameters,

    template< typename F >
    struct my
    {
        // same as 'typedef F<int> t' if F would be a TTP
        typedef typename lambda<F>::type f_;
        typedef typename apply1<f_,int>::type t;
    };

    template<typename T, typename U = T> struct her {};

    int main()
    {
        sizeof(my< her<_1> >); // ok!
        return 0;
    }

and is, in fact, superior to the GCC and Borland behavior, because with
lambda it's possible to do an arbitrary currying,

        sizeof(my< her<int,_1> >); // ok too!

and yet this inflexibility it so successfully fights with seems to be a very
important part on the library's own implementation :).

> You're saying that the compile-time lambda doesn't actually
> work with GCC because it needs working TTP to implement
> it?

It works with anything but currying of class templates that have default
template parameters, e.g.

    template< typename T, typename U > struct my {};
    template< typename T, typename U = int > struct her {};

    typedef typename lambda< my<_1,int> >::type t1; // ok
    typedef typename lambda< her<_1> >::type t2; // #1 - the ambiguity error
we've talked about

Unfortunately, MPL uses the default template parameters for almost every
predefined function object like 'logical_or' or 'plus' (to support more
invocations with than 2 arguments)..

> If so, that doesn't make sense to me because we know we
> can always replace TTP with generators.

It's matching of the class template specializations like

    template< typename T >
    struct lambda
    {
        typedef T type;
    };

    template<
          typename T
        , template< typename > class F
>
    struct lambda< F<T> >
    {
        typedef /**/ type;
    };

    template<
          typename T1
        , typename T2
        , template< typename, typename > class F
>
    struct lambda< F<T1,T2> >
    {
        typedef /**/ type;
    };

that cause GCC to fail in line #1, and I am afraid there is no way we can
get away with generators here.. :)


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