C++ boost::Adapter::使用boost::range_detail::default_constructible_unary_fn_wrapper"过滤的核心转储;断言'm#u impl';“失败”;

C++ boost::Adapter::使用boost::range_detail::default_constructible_unary_fn_wrapper"过滤的核心转储;断言'm#u impl';“失败”;,c++,boost,c++14,boost-range,C++,Boost,C++14,Boost Range,运行此代码时,我在boost::range\u detail::default\u constructible\u unary\u fn\u包装器中遇到断言失败。断言似乎正在检查functor是否已在筛选器对象内初始化 #include <boost/range/adaptor/filtered.hpp> #include <iomanip> #include <iostream> #include <map> #include <unor

运行此代码时,我在
boost::range\u detail::default\u constructible\u unary\u fn\u包装器中遇到断言失败。断言似乎正在检查functor是否已在筛选器对象内初始化

#include <boost/range/adaptor/filtered.hpp>

#include <iomanip>
#include <iostream>
#include <map>
#include <unordered_map>
#include <vector>

template<class RangeType>
static auto get_range_and_range_size(const RangeType& in_range, std::input_iterator_tag) -> auto {
    /*
     * we have an InputRange, but we need to know the size of the range.
     * so we eagerly copy the values into a vector so we can get the size of the range
     * and also return the range.
     * */
    auto out_range = std::vector<decltype(*std::begin(in_range))>(
        std::begin(in_range),
        std::end(in_range)
    );

    return std::make_tuple(std::move(out_range), out_range.size());
}

template<class RangeType>
static auto get_range_and_range_size(const RangeType& in_range, std::forward_iterator_tag) -> auto {
    return std::make_tuple(std::ref(in_range), boost::distance(in_range));
}

struct Cache {
    std::unordered_map<int, int> m_map;

    template<class RangeT>
    auto Insert(RangeT in_range) -> void {
        typename std::iterator_traits<
            decltype(std::begin(in_range))
        >::iterator_category iterator_category;

        std::cout << "No core dump yet!\n";

        auto range_and_range_size = get_range_and_range_size(
            boost::adaptors::filter(
                in_range,
                /*
                 * filter out any keys that are already in the cache and NOT TTLed yet
                 * */
                [this](const auto& key_value) -> bool {
                    const auto find_itr = m_map.find(key_value.first);

                    return (m_map.end() == find_itr)    /*  the key was not in the cache    */
                           || hasTTLed(find_itr->second);  /*  the key was in the cache but its value has TTLed  */
                }
            ),
            iterator_category
        );

        for(auto&& key_value : std::get<0>(range_and_range_size)) {
            m_map.emplace(key_value);
        }

        std::cout << "Can't reach this code. :(\n";
    }

    auto hasTTLed(int) const noexcept -> bool {
        /*
         *  TTL impl goes here
         */
        return false;
    }
};

auto main(int, char*[]) -> int {
    Cache a{};

    std::vector<std::pair<int, int>> v{
        {0, 0},
        {1, 1},
        {2, 2},
        {3, 3}
    };

    a.Insert(v);

    std::map<int, int> b{
        {0, 1},
        {1, 0},
        {2, 1},
        {3, 1}
    };

    a.Insert(b);
}
#包括
#包括
#包括
#包括
#包括
#包括
模板
静态自动获取范围和范围大小(常量范围类型和范围内,标准::输入迭代器标记)->auto{
/*
*我们有一个输入范围,但我们需要知道范围的大小。
*所以我们急切地将这些值复制到一个向量中,这样我们就可以得到范围的大小
*并返回范围。
* */
自动输出范围=标准::向量(
标准::开始(在_范围内),
标准::结束(在_范围内)
);
返回std::make_tuple(std::move(out_range),out_range.size());
}
模板
静态自动获取范围和范围大小(常量范围类型和范围内,std::forward\u迭代器标记)->auto{
返回std::make_tuple(std::ref(在_范围内),boost::distance(在_范围内));
}
结构缓存{
std::无序图m\u图;
模板
自动插入(范围在\u范围内)->void{
typename std::迭代器<
decltype(std::begin(在_范围内))
>::迭代器\类别迭代器\类别;
标准:库特布尔{
const auto find_itr=m_map.find(key_value.first);
return(m_map.end()==find_itr)/*密钥不在缓存中*/
||hasTTLed(find_itr->second);/*该键在缓存中,但其值已被删除*/
}
),
迭代器类
);
for(自动和键控值:std::get(范围和大小)){
m_地图布设(关键值);
}
标准:库特布尔{
/*
*TTL impl在这里
*/
返回false;
}
};
自动主(int,char*[])->int{
缓存a{};
向量v{
{0, 0},
{1, 1},
{2, 2},
{3, 3}
};
a、 插入(v);
地图b{
{0, 1},
{1, 0},
{2, 1},
{3, 1}
};
a、 插入(b);
}
我用coliru使用的任何版本的boost以及1.60都可以实现这一点

复制于科里鲁


你能帮我理解a)这里发生了什么,b)我如何修复它吗?

这是一个终生的问题

问题出现在
get\u range\u和\u range\u size
中,它在捕获
const RangeType&
时本应捕获
RangeType&&
。将
std::ref
返回到以这种方式捕获的临时对象会导致调用代码中作用于
range\u和\u range\u size
的未初始化范围

这些
get\u range\u和\u range\u size
的定义解决了这个问题

template<class RangeType>
static auto get_range_and_range_size(RangeType&& in_range, std::input_iterator_tag) -> auto {
    /*
     * we have an InputRange, but we need to know the size of the range.
     * so we eagerly copy the values into a vector so we can get the size of the range
     * and also return the range.
     * */
    auto out_range = std::vector<decltype(*std::begin(in_range))>(
        std::begin(in_range),
        std::end(in_range)
    );

    const auto out_size = out_range.size(); /*  capture the value before moving the container   */
    return std::make_tuple(std::move(out_range), out_size);
}

template<class RangeType>
static auto get_range_and_range_size(RangeType&& in_range, std::forward_iterator_tag) -> auto {
    const auto size = boost::distance(in_range); /*  capture the value before moving the container   */
    return std::make_tuple(std::move(in_range), size);
}
模板
静态自动获取范围大小(RangeType&&in范围,std::input迭代器标记)->auto{
/*
*我们有一个输入范围,但我们需要知道范围的大小。
*所以我们急切地将这些值复制到一个向量中,这样我们就可以得到范围的大小
*并返回范围。
* */
自动输出范围=标准::向量(
标准::开始(在_范围内),
标准::结束(在_范围内)
);
const auto out_size=out_range.size();/*在移动容器之前捕获值*/
返回std::make_元组(std::move(out_范围),out_大小);
}
模板
静态自动获取范围大小(RangeType&&in范围,std::forward迭代器标记)->auto{
const auto size=boost::distance(在_范围内);/*在移动容器之前捕获值*/
返回std::make\ tuple(std::move(在\范围内),size);
}

从断言失败的名称来看,我的猜测是
过滤器
适配器需要一个默认的可构造谓词,而lambda不是默认的可构造谓词。不过,它没有在文档中的任何地方命名该需求。(这里吹毛求疵,但如果没有捕获,lambda可能是默认可构造的)请参阅。
filter\u iterator
的文档确实提到谓词需要是默认可构造的。在第二个重载中调用
make\u tuple
时,您应该
std::forward(in\u range)
。我之前的评论中关于必须获取
size()
分别。
make\u tuple
perfect转发它的参数,所以调用它时只绑定引用,实际上没有移动构造,所以调用
.size()第二个参数中的
很好。谢谢。我假设在使用
input\u iterator\u tag
函数的情况下,我仍然需要
std::move
向量,因为它不是临时的。