在下面的代码中(简化用于演示):
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");
哼!