与提升::MPL 占位符评估不一致的行为



在下面的代码中(简化用于演示):

  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;

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>')


问题:为什么mpl::_1占位符在std::is_same中正确变换/替换为double,但在std::common_type却没有?有没有解决方法?


您在应用 lambda 之前访问嵌套的 std::common_type ::type,从而强制过于急切的实例化。用std::common_type<double, mpl::_1>代替typename std::common_type<double, mpl::_1>::type,你应该一切都很好。

编辑:为糟糕的建议道歉。我没看清楚你在做什么。麻烦的是,mpl::apply首先通过 mpl::lambda 运行您的占位符表达式将其转换为 lambda 表达式。这将导致std::common_type<double, mpl::_1>被包装在 mpl::protect 中,这将阻止它在第一次传递中被评估,并且mpl::if_不会在第二次传递中评估它,因为它将其第二个和第三个参数视为纯类型,而不是占位符表达式。您可以使用mpl::bind强制在mpl::if_之前评估std::common_type。这样,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");

哼!

最新更新