boost::mpl::eval_if延迟求值疑问:为何apply触发mpl_::arg提前求值?
Boost.MPL
eval_if条件参数的编译问题解析 问题背景
基于Boost.MPL实现next_if模板的代码如下:
#include <boost/mpl/apply.hpp> #include <boost/mpl/vector_c.hpp> #include <boost/mpl/transform.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/mpl/not_equal_to.hpp> #include <boost/mpl/greater.hpp> #include <boost/mpl/less.hpp> #include <boost/mpl/plus.hpp> #include <boost/mpl/minus.hpp> #include <boost/mpl/multiplies.hpp> #include <boost/type_traits/is_scalar.hpp> template <typename N, typename Predicate > struct next_if : boost::mpl::eval_if< typename boost::mpl::apply<Predicate, N>::type, // boost::mpl::apply<Predicate, N>, boost::mpl::next<N>, boost::mpl::identity<N> > {}; template <typename N> struct predic : boost::mpl::bool_<false> { }; template <int N> struct predic <boost::mpl::int_<N>> : boost::mpl::bool_< (N > 0 && N < 100) > { }; int main() { static_assert(std::is_same_v<next_if<boost::mpl::int_<10>, predic<boost::mpl::_1>>::type, boost::mpl::int_<11>>, ""); return 0; }
现象对比
- 当条件参数使用
typename boost::mpl::apply<Predicate, N>::type时,代码编译正常并通过断言。 - 改为直接传入
boost::mpl::apply<Predicate, N>时,编译失败,报错如下:
/opt/compiler-explorer/libs/boost_1_64_0/boost/mpl/if.hpp: In instantiation of 'struct boost::mpl::if_<boost::mpl::apply<predic<mpl_::arg<1> >, mpl_::int_<10>, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::mpl::next<mpl_::int_<10> >, boost::mpl::identity<mpl_::int_<10> > >': /opt/compiler-explorer/libs/boost_1_64_0/boost/mpl/eval_if.hpp:37:41: required from 'struct boost::mpl::eval_if<boost::mpl::apply<predic<mpl_::arg<1> >, mpl_::int_<10>, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::mpl::next<mpl_::int_<10> >, boost::mpl::identity<mpl_::int_<10> > >' <source>:19:8: required from 'struct next_if<mpl_::int_<10>, predic<mpl_::arg<1> > >' <source>:40:87: required from here /opt/compiler-explorer/libs/boost_1_64_0/boost/mpl/aux_/static_cast.hpp:24:47: error: 'value' is not a member of 'boost::mpl::apply<predic<mpl_::arg<1> >, mpl_::int_<10>, mpl_::na, mpl_::na, mpl_::na, mpl_::na>' 24 | # define BOOST_MPL_AUX_STATIC_CAST(T, expr) static_cast<T>(expr) | ^~~~~~~~~~~~~~~~~~~~
问题解答
核心差异分析
Boost.MPL的eval_if要求第一个参数必须是带有value静态成员的布尔元类型(如boost::mpl::bool_<true>),而非元函数应用的包装类型。
正确写法的逻辑
boost::mpl::apply<Predicate, N>是元函数应用的模板实例,它本身不是布尔元类型。通过::type获取其内部结果后,得到的是predic<boost::mpl::int_<10>>——这个特化类型继承自boost::mpl::bool_<true>,拥有eval_if需要的value成员。- 此时
apply会正确将占位符mpl_::_1替换为N(即int_<10>),实例化对应的predic特化版本,最终生成符合要求的布尔元类型。
错误写法的问题
boost::mpl::apply<Predicate, N>本身只是一个“元函数应用的包装结构体”,并没有定义value成员。而eval_if内部会尝试读取条件类型的value来判断分支,因此编译器会抛出“'value' is not a member of ...”的错误。- 这并非占位符提前求值的问题,而是你传入的类型不符合
eval_if的参数要求——apply的实例是元函数执行的“过程载体”,而非执行后的结果类型。
总结:eval_if需要的是元函数执行完毕后的结果类型,你必须通过typename ...::type提取apply的最终结果,才能满足其参数要求。
内容的提问来源于stack exchange,提问作者Xiong Zou
相关产品推荐
相关产品推荐

