You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>),而非元函数应用的包装类型。

  1. 正确写法的逻辑

    • 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特化版本,最终生成符合要求的布尔元类型。
  2. 错误写法的问题

    • 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 15:47:03