Проблемы с использованием mpl :: if_, boost :: function и typedef для void - PullRequest
1 голос
/ 24 ноября 2011

Я новичок в библиотеке Boost.MPL, и у меня возникли некоторые "проблемы новичков"

Посмотрите на этот образец:

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;
}

При компиляции получаю:

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’

В чем здесь проблема, и как я могу ее решить?

Насколько я понимаю, только выбранная часть mpl::if_ должна быть оценена компилятором ....

1 Ответ

3 голосов
/ 24 ноября 2011

Прежде всего, чтобы объяснить ошибку, следует отметить, что использование typedef для void в списке параметров является ошибкой. Эти два отчета об ошибках GCC ( 32058 и 9278 ) описывают проблему, и указывают на то, что это требование стандарта.

Таким образом, в соответствии с §8.3.5 / 2 стандарта, это законно:

void foo(void);

пока это не так:

typedef void type;
void foo(type);

Это объясняет, почему вам понадобился if_ в первую очередь. Теперь, чтобы объяснить, почему у вас все еще есть ошибка, вы должны понимать, что отложенная оценка в MPL применима только к метафункциям: пока вы не обращаетесь к type внутри мета-функции, она не оценивается. Здесь аргументы if_ не оцениваются (они не могли, поскольку они не являются метафункциями), но это не означает, что они не создаются.

Чтобы преодолеть эту проблему, вы можете встроить function экземпляры в метафункции, которые можно лениво оценивать:

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() { }
};

Таким образом, ошибочное void (typedef_to_void) никогда не появляется.

Лучшим решением было бы даже специализировать метафункцию get_function для случая void:

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() { }
};

Не нужно больше if_ необходимо!

...