升压eval_if的延迟评估

时间:2018-12-11 21:14:13

标签: c++ boost lazy-evaluation

我认为我对eval_if的懒惰有误解。

以下代码是根据众所周知的成员检测机制进行调整的, 我尝试在其中添加成员也应该可以转换为特定类型的功能。

image

但是执行以下操作时:

<Image source={{uri:uri}} style={{width: 200, height: 200}} />

我收到以下错误:

template <typename T, typename P = size_t>
struct has_height
{
  private:
    using Yes = char[2];
    using No = char[1];

    struct Fallback
    {
        P height;
    };
    struct Derived : T, Fallback
    {
    };

    template <class U>
    static No &test(decltype(U::height) *);

    template <typename U>
    static Yes &test(U *);

  public:
    static constexpr bool has_member = sizeof(test<Derived>(nullptr)) == sizeof(Yes);

    using value_type = std::integral_constant<bool, has_member>;

    static constexpr bool value = boost::mpl::eval_if<
        value_type,
        std::is_convertible<decltype(T::height), P>,
        boost::mpl::identity<std::false_type>>::type::value;
};

template <typename T, typename P>
const bool has_height<T, P>::value;

template <typename T, typename P>
const bool has_height<T, P>::has_member;

我理解编译器在说什么,只是不明白为什么。我的假设 这是因为条件为假(已测试),所以不评估第二个参数(std :: is_convertible)。

对此事的任何澄清将不胜感激,可能的修复方法也将很好;)

Auke

1 个答案:

答案 0 :(得分:2)

如果您忘记了boost::mpl一秒钟,而只是看一下它的简化形式:

eval_if<value_type, A, B>::type::value

应该更加清楚,AB都被评估为第二和第三模板参数,必须对其进行评估。这样就不会偷懒了。

如果要实现“懒惰”行为,则可以使用模板专门化。

template<bool, class T, class P>
struct has_height_helper {
   // `true` case. Evaluate `T::height`
   static constexpr bool value = std::is_convertible<decltype(T::height), P>::value;
}

template<class T, class P>
struct has_height_helper<false, T, P> {
    static constexpr bool value = false;
}

// And now use the helper in the class
static constexpr bool value = has_height_helper<has_member, T, P>::value;

由于模板规范化基本上根据所使用的规范化“隐藏”代码。

另一种选择是带有if constexpr的constexpr函数来隐藏代码:

template<bool has_member, class T, class P>
constexpr bool has_height_helper() {
    if constexpr (has_member) {
        return std::is_convertible<decltype(T::height), P>::value;
    } else {
        return false;
    }
}

您可以将其引入结构:

template <typename T, typename P = size_t>
struct has_height
{
  private:
    struct Fallback
    {
        P height;
    };
    struct Derived : T, Fallback
    {
    };

    template <class U>
    constexpr static bool test(decltype(U::height) *) {
        return std::is_convertible<decltype(T::height), P>::value;
    }

    template <typename U>
    constexpr static int test(U *) {
        // Basically return any non-bool false so we can tell the difference
        return 0;
    }

  public:
    static constexpr bool has_member = std::is_same<test<Derived>(nullptr), bool>::value;

    using value_type = std::integral_constant<bool, has_member>;

    static constexpr bool value = test<Derived>(nullptr);
};