1

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....

Luc Touraille
  • 79,925
  • 15
  • 92
  • 137
Allan
  • 4,562
  • 8
  • 38
  • 59
  • I get `'result_type' in namespace 'boost::function_types' does not name a type` – BЈовић Nov 24 '11 at 14:22
  • `P` is not used in `TTT` declaration, is it normal or is it a typo (we don't know what you are trying to achieve, so it is hard to tell)? – Luc Touraille Nov 24 '11 at 14:51
  • 1
    Why the downvote and the close vote? This is a perfectly reasonable question that can be answered and could help others. It made me learn that using a typedef to void in a parameter list is an error, which seems a sufficient justification for the question :). And it can help other people using MPL and/or `boost/std::function`. Perhaps the title could be rephrased since the issue is not so much about `function_types` but more about `function` and function signatures in general. – Luc Touraille Nov 24 '11 at 14:58

1 Answers1

3

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!

Luc Touraille
  • 79,925
  • 15
  • 92
  • 137