
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.