为什么range-v3中的yield要求默认构造函数?

6

我试图理解,为什么yield函数族需要类默认可构造。

在下面的例子中,只有当CNum有默认构造函数时,vnums1行才会编译。而vnums2行则不需要默认构造函数。

我正在使用Visual Studio 2017和Range-V3-VS2015。谢谢!

#include <range/v3/all.hpp>

struct CNum
{
    // CNum() = default;
    explicit CNum(int num) : m_num(num) {}
    int m_num;
};

int main()
{
    auto ints = ranges::view::ints(0, 10);

    // this compiles only of CNum has a default constructor
    auto vnums1 = ints
        | ranges::view::for_each([](int num) { return ranges::yield_if(num % 2, CNum(num)); })
        | ranges::to_vector;

    // this compiles even if CNum does not have a default constructor
    auto vnums2 = ints
        | ranges::view::remove_if([](int num) { return num % 2 == 0; })
        | ranges::view::transform([](int num) { return CNum(num); })
        | ranges::to_vector;

    return 0;
}
2个回答

6

我们刚刚更改了代码,不再需要DefaultConstructible。git pull并享受吧。


太好了。谢谢。Microsoft/Range-V3-VS2015的维护者没有从ericniebler/range-v3中获取新的更改。有人有建议吗?我该如何使用VC++ 2017获取最新的位? - CodeAndLearn
不幸的是,你最好的选择是fork Microsoft/Range-V3-VS2015仓库并自己进行更改。 - Eric Niebler

2
您需要默认构造函数来使用ranges::yield_if的原因是,它所使用的机制要求类型具有默认构造能力。 如果我们查看代码,我们会发现:
struct yield_if_fn
{
    template<typename V>
    repeat_n_view<V> operator()(bool b, V v) const
    {
        return view::repeat_n(std::move(v), b ? 1 : 0);
    }
};

/// \relates yield_if_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(yield_if_fn, yield_if)

我们可以看到它调用了view::repeat_n。查看该代码,我们得到:

repeat_n_view<Val> operator()(Val value, std::ptrdiff_t n) const
{
    return repeat_n_view<Val>{std::move(value), n};
}

如果我们看一下repeat_n_view,我们会发现:

// Ordinarily, a view shouldn't contain its elements. This is so that copying
// and assigning ranges is O(1), and also so that in the event of element
// mutation, all the copies of the range see the mutation the same way. The
// repeat_n_view *does* own its lone element, though. This is OK because:
//  - O(N) copying is fine when N==1 as it is in this case, and
//  - The element is immutable, so there is no potential for incorrect
//    semantics.

struct repeat_n_view
  : view_facade<repeat_n_view<Val>, finite>
{
private:
    friend range_access;
    Val value_;
    std::ptrdiff_t n_;

    // ...
public:
    repeat_n_view() = default;
    constexpr repeat_n_view(Val value, std::ptrdiff_t n)
      : value_(detail::move(value)), n_((RANGES_EXPECT(0 <= n), n))
    {}
    constexpr std::size_t size() const
    {
        return static_cast<std::size_t>(n_);
    }
};

我们从评论中可以看出,这是一个设计决策,并且由于这个设计,你需要让你的类型具有默认构造函数。Eric描述了所需的类型为“SemiRegular”,其中文档记录为需要具有默认构造函数、复制和移动构造函数以及析构函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接