Boost logo

Boost :

Subject: Re: [boost] Compiler error in gcc3+ involving template template parameter and default parameters
From: Brent Spillner (spillner_at_[hidden])
Date: 2011-01-16 17:55:17

On 01/16/2011 8:34 AM, Edward Diener wrote:
>That is very nice to say, but the library is for Boost which does try to
>still support gcc3+. I know it compiles without error in gcc4+. I should
>have been more explicit when I notated 'gcc3+' to ex0plain that I meant
>gcc3 versions and not gcc4 versions.

I would have dropped the '+' ;-) I'm all about supporting the widest
possible variety of compilers, but note that the last GCC 3 release
was nearly five years ago. I'm sure that there are plenty of other
things in Boost that it can't handle.

>Those are just specializations of:
>template<class T>
>struct eval;
>There is no reason SFINAE should be involved.

It's the same principle; rather than attempting to substitute class
members, the compiler is substituting the parameters of the template
class F. At any rate, I don't know another name for the concept.

>> template<class T, class P = noparam>
>> struct ptmf {
>>    typedef int type;
>>    typedef ptmf<T, P>  is_unary;
>> };
>> template<class T, class P1, class P2>
>> struct other {
>>    typedef int type;
>>    typedef other<T, P1, P2>  is_binary;
>> };
>> template<template<class>  class F, class P1>
>> struct eval<F<P1>  >  : typename F<typename P1::type>::is_unary {};
>> template<template<class,class>  class F, class P1, class P2>
>> struct eval<F<P1, P2>  >  : typename F<typename P1::type, typename
>> P2::type>::is_binary {};
>I do not follow this. Your is_unary and is_binary are typedefs within
>'ptmf' and 'other' templates.

The idea was to give g++ a little more information to help resolve the
eval<> ambiguity; when 'ptmf' is substituted for 'F', there is no
nested ::is_binary and the second specialization cannot apply, but the
first specialization resolves and in fact yields the same type that it
would have without the '::is_unary'. Unfortunately, that doesn't seem
to be enough help for GCC 3.4.6.

I did, however, get your example to compile by refactoring a bit: if
you change the template parameters for ptmf to 'template<class T,
class P = noparam, class Unused = noparam>', then you can eliminate
the first specialization of eval<> but provide additional
specializations for the cases where P2 is noparam or P1 and P2 are
both noparam, e.g.

struct nullary_op {}; struct unary_op {}; struct binary_op {};

template <template<class,class> class F, class P1, class P2>
struct eval<F<P1,P2> > :
  F<typename P1::type,typename P2::type> { typedef binary_op category; };

template <template <class,class> class F, class P1>
struct eval<F<P1,noparam> > :
  F<typename P1::type,noparam> { typedef unary_op category; };

template <template <class,class> class F>
struct eval<F<noparam,noparam> > :
  F<noparam,noparam> { typedef nullary_op category; };

where ::category is just a type tag to help you differentiate between
the types of eval<> elsewhere in the framework. This compiles as-is
under GCC 3.4.6, and requires that you change the first declaration of
eval ('template <class F> struct eval;') to a concrete definition
('template <class F> struct eval {};') under GCC 4.4.4 and 4.5.2 (also
legal under 3.4.6.) I don't know how well this solution fits into the
rest of your library, but I hope it at least provides some ideas.

Boost list run by bdawes at, gregod at, cpdaniel at, john at