为什么 range-v3 yield 需要默认构造函数
why does range-v3 yield require default constructor
我想了解,为什么 yield 函数族要求 class 是默认可构造的?
在下面的示例中,仅当 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;
}
您需要默认构造函数才能使用的原因 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
,记录为
it needs to be default constructable, copy and move constructable, and destructable.
我们只是将代码更改为不需要 DefaultConstructible。 git 尽情享受吧。
我想了解,为什么 yield 函数族要求 class 是默认可构造的?
在下面的示例中,仅当 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;
}
您需要默认构造函数才能使用的原因 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
,记录为
it needs to be default constructable, copy and move constructable, and destructable.
我们只是将代码更改为不需要 DefaultConstructible。 git 尽情享受吧。