运行此代码时,boost::range_detail::default_constructible_unary_fn_wrapper
内的断言失败。断言似乎是检查仿函数是否已在过滤器对象内初始化。
#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);
}
无论coliru使用的是什么版本的增强版,我都能得到这个,以及1.60。
转载于coliru here。
你能帮助我理解a)这里发生了什么,以及b)我是如何解决的?
答案 0 :(得分:2)
这是一生的问题。
问题发生在get_range_and_range_size
,当它应该捕获const RangeType&
时捕获了RangeType&&
。将std::ref
返回到以此方式捕获的临时值会导致在代码range_and_range_size
上调用未初始化的范围。
get_range_and_range_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);
}