boost :: mpl占位符评估的行为不一致

eth*_*ice 7 c++ boost boost-mpl template-meta-programming c++11

在以下代码中(为演示而简化):

  namespace mpl = boost::mpl;

  using if1 = mpl::if_<std::is_same<double, mpl::_1>, double, void>;
//using if2 = mpl::if_<std::is_same<double, mpl::_1>, typename std::common_type<double, mpl::_1>::type, void>;

  using apply1 = boost::mpl::apply<if1, double>::type;
//using apply2 = boost::mpl::apply<if2, double>::type;
Run Code Online (Sandbox Code Playgroud)

std::is_same<double, mpl::_1>,占位符被正确替换double,就好像实例化明确std::is_same<double, double>导致正确/预期的行为.

但是,在std::common_type<double, mpl::_1>占位符中没有替换占位符,就好像实例化是明确的std::common_type<double, mpl_::arg<1>>,这会导致以下错误,因为显然没有"常见"类型:

error: incompatible operand types ('double' and 'mpl_::arg<1>')
Run Code Online (Sandbox Code Playgroud)


问题:为什么mpl::_1占位符正确转换/置换doublestd::is_same,而不是std::common_type?有解决方法吗?


Eri*_*ler 6

你通过访问嵌套迫使急于实例::typestd::common_type应用拉姆达之前.替换typename std::common_type<double, mpl::_1>::typestd::common_type<double, mpl::_1>,你应该都很好.

编辑:抱歉不好的建议.我没看到你在做什么.麻烦的是,mpl::apply首先运行它会将占位符表达式转换为lambda表达式mpl::lambda.这将导致std::common_type<double, mpl::_1>包装在一个mpl::protect,它将阻止它在第一次传递中被评估,并且mpl::if_不会在第二次传递中评估它,因为它将其第二个和第三个参数视为普通类型,而不是占位符表达式.您可以使用mpl::bind强制std::common_type进行评估之前 mpl::if_.那样,mpl::if_看到了if_<some-condition, double, void>,一切都是对的.

#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/bind.hpp>
#include <boost/mpl/quote.hpp>

namespace mpl = boost::mpl;

template<typename T, typename U> using common_type2 = std::common_type<T,U>;
using if2 = mpl::if_<
                std::is_same<double, mpl::_1>,
                mpl::bind<mpl::quote2<common_type2>, double, mpl::_1>,
                void>;
using apply2 = boost::mpl::apply<if2, double>::type;
static_assert(std::is_same<apply2, double>::value, "works");
Run Code Online (Sandbox Code Playgroud)

HTH!