Question

I'm new to the Boost.MPL library, and have some "beginners-problems"

Look at this sample:

template < typename F >
struct A {
   typedef boost::function_types::parameter_types<F> P;
   typedef typename boost::function_types::result_type<F>::type R;

   typedef typename boost::mpl::if_< boost::is_same< R, void >,
                                     boost::function< void ( void ) > ,
                                     boost::function< void ( R ) > >::type TTT;
   A() { }
};

int main(int argc, const char *argv[]) {
   A<int(int, float)>  ok; // working
   A<void(int, float)> compile_error; // non-working

   return 0;
}

When compiling I get:

xxx.cxx: In instantiation of ‘A<void(int, float)>’:
xxx.cxx:108:25:   instantiated from here
xxx.cxx:100:77: error: invalid parameter type
‘boost::mpl::aux::wrapped_type<boost::mpl::aux::type_wrapper<void>
>::type’
xxx.cxx:100:77: error: in declaration ‘A<F>::TTT’

What is the problem here, and how can I solve it?

To my understanding, only the selected part of mpl::if_ should be evaluated by the compiler....

Was it helpful?

Solution

First of all, to explain the error, it should be noted that using a typedef to void in a parameter list is an error. These two GCC bug reports (32058 and 9278) describe the problem, an point out that this is requirement from the standard.

So basically, according to §8.3.5/2 of the standard, this is legal:

void foo(void);

while this is not:

typedef void type;
void foo(type);

This explains why you needed the if_ in the first place. Now to explain why you still have the error, you need to understand that lazy evaluation in MPL only apply to metafunctions: as long as you don't access the type inside a metafunction, it is not evaluated. Here, the if_'s arguments are not evaluated (they could not since they are not metafunctions), but that does not mean that they are not instantiated.

To overcome this issue, you could embed the function instantiations into metafunctions that could be lazily evaluated:

template < typename R, typename P >
struct get_function
{
  typedef boost::function< R (P) > type;
};

template < typename F >
struct A {
    typedef boost::function_types::parameter_types<F> P;
    typedef typename boost::function_types::result_type<F>::type R;

    typedef typename 
        boost::mpl::if_< 
            boost::is_same< R, void >,
            boost::mpl::identity< boost::function< void (void) > > ,
            get_function< void, R >
        >::type::type TTT;

    A() { }
};

This way, the erroneous void (typedef_to_void) never appears.

A better solution would even be to specialize the get_function metafunction for the void case:

template < typename R, typename P >
struct get_function
{
  typedef boost::function< R (P) > type;
};

template < typename R >
struct get_function< R, void >
{
    typedef boost::function< R (void) > type;
};

template < typename F >
struct A {
    typedef boost::function_types::parameter_types<F> P;
    typedef typename boost::function_types::result_type<F>::type R;

    typedef typename get_function< void, R >::type TTT;

    A() { }
};

No more if_ needed!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top