【发布时间】:2018-07-18 11:24:05
【问题描述】:
我正在尝试使用范围 v3 实现蒙面范围视图。不知何故,我最终陷入了我的实施
ranges::view::masker(datarange, mask)
有效,但管道版本
ranges::view::all(datarange) | ranges::view::masker(mask)
没有,尽管使用 operators 的内部结构,掩码正确到达。 (我将masker 的实现放入ranges::view 命名空间,虽然它不是范围v3 的一部分)。
我的测试程序比较琐碎,创建一些小部件和一个无意义的掩码
class Widget
{
private:
int m_int{0};
public:
Widget() {}
Widget( int i ) : m_int( i ) {}
int the_int() const { return m_int; }
};
inline std::ostream& operator<<( std::ostream& str, const Widget& obj )
{
str << '\t' << obj.the_int();
return str;
}
int main()
{
std::vector<Widget> widgets;
std::vector<bool> mask;
for ( auto i : ranges::view::indices( 24 ) ) {
widgets.emplace_back( i );
mask.push_back( i % 3 != 1 );
}
std::cout << "wrapped" << std::endl;
for ( auto& el : ranges::view::masker( widgets, mask ) ) {
std::cout << el << std::endl;
}
std::cout << std::endl;
std::cout << std::endl;
std::cout << "piped" << std::endl;
for ( auto& el : ranges::view::all( widgets ) | ranges::view::masker( mask ) ) {
std::cout << el << std::endl;
}
return 0;
}
忽略命名空间和调试打印输出 masker 只是将数据范围和掩码压缩在一起,过滤掩码并将小部件作为视图返回:
struct mask_fn
{
template<typename Rng, typename Msk>
auto operator()(Rng&& rng, Msk&& msk) const
{
CONCEPT_ASSERT(Range<Rng>());
CONCEPT_ASSERT(Range<Msk>());
return ranges::view::zip(std::forward<Rng>(rng),
std::forward<Msk>(msk)) |
ranges::view::filter([](auto&& range_item) -> bool {
return range_item.second;
}) |
ranges::view::transform(
[](auto&& range_item) -> decltype(auto) {
return range_item.first;
});
}
template<typename Msk>
auto operator()(Msk&& msk) const -> decltype(
make_pipeable(std::bind(*this, std::placeholders::_1,
protect(std::forward<Msk>(msk)))))
{
CONCEPT_ASSERT(Range<Msk>());
return make_pipeable(
std::bind(*this,
std::placeholders::_1,
protect(std::forward<Msk>(msk))));
}
};
RANGES_INLINE_VARIABLE(mask_fn, masker)
上面的程序打算打印两次相同的结果范围,但我只得到:
wrapped
0
2
3
5
6
8
9
11
12
14
15
17
18
20
21
23
piped
因此,当使用auto operator()(Rng&& rng, Msk&& msk) const 时,正确的小部件会循环,auto operator()(Msk&& msk) const 的版本不会返回任何内容。
我尝试向前者添加一些调试打印输出(因为它最终被后者调用)并观察掩码正确到达。
struct mask_fn
{
template<typename Rng, typename Msk>
auto operator()(Rng&& rng, Msk&& msk) const
{
CONCEPT_ASSERT(Range<Rng>());
CONCEPT_ASSERT(Range<Msk>());
for(auto t :
ranges::view::zip(rng, msk) |
ranges::view::filter([](auto&& range_item) ->
bool {
return range_item.second;
}) |
ranges::view::transform(
[](auto&& range_item) -> decltype(auto) {
return range_item.first;
}))
std::cout << "w: " << t << std::endl;
return ranges::view::zip(std::forward<Rng>(rng),
std::forward<Msk>(msk)) |
ranges::view::filter([](auto&& range_item) -> bool {
std::cout << "checking widget "
<< range_item.first << std::endl;
std::cout << "returning " << range_item.second
<< std::endl;
return range_item.second;
}) |
ranges::view::transform(
[](auto&& range_item) -> decltype(auto) {
return range_item.first;
});
}
template<typename Msk>
auto operator()(Msk&& msk) const -> decltype(
make_pipeable(std::bind(*this, std::placeholders::_1,
protect(std::forward<Msk>(msk)))))
{
CONCEPT_ASSERT(Range<Msk>());
return make_pipeable(
std::bind(*this,
std::placeholders::_1,
protect(std::forward<Msk>(msk))));
}
};
RANGES_INLINE_VARIABLE(mask_fn, masker)
(稍微削减输出)可以看到,使用operator() 内的假定返回范围我循环了正确的小部件,但返回行中的 lambdas 内的打印输出显示所有项目的“假”标志。
wrapped
w: 0
w: 2
w: 3
w: 5
<snap>
w: 20
w: 21
w: 23
checking widget 0
returning 1
0
checking widget 1
returning 0
checking widget 2
returning 1
2
checking widget 3
returning 1
3
<snap>
checking widget 22
returning 0
checking widget 23
returning 1
23
piped
w: 0
w: 2
w: 3
w: 5
<snap>
w: 20
w: 21
w: 23
checking widget 0
returning 0
checking widget 1
returning 0
checking widget 2
returning 0
checking widget 3
returning 0
<snap>
checking widget 22
returning 0
checking widget 23
目前我最好的猜测是我在某处搞砸了protect、std::forward、&& 或std::move,尽管我试图尽可能地贴近filter.hpp(因为我认为我已经很好地理解了它)并且还尝试了一些随机添加/删除&符号和转发但没有成功。
有什么建议可以解决这个问题吗? (理想情况下,还要解释发生了什么?)。
提前致谢。
脚注:我目前不关心 c++11 的兼容性。
编辑:
我把这个烂摊子推到github。
【问题讨论】: