使用mpl::if_、boost::函数和void类型定义的问题

Problems using mpl::if_, boost::function, and a typedef to void

本文关键字:类型 void 定义 问题 boost if mpl 使用 函数      更新时间:2023-10-16

我是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_中选定的部分求值....

首先,要解释这个错误,应该注意在参数列表中对void使用类型定义是一个错误。这两个GCC bug报告(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)就不会出现。

一个更好的解决方案甚至是为void的情况专门化get_function元函数:

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_ !