假设我有一个函数 unique_count
可以计算任何未排序范围内唯一元素的数量:
template<typename InputIt>
std::size_t unique_count(InputIt first, InputIt last)
{
using T = typename std::iterator_traits<InputIt>::value_type;
std::vector</* ??? */> v(first, last);
std::sort(v.begin(), v.end());
return std::distance(v.begin(),
std::unique(v.begin(), v.end()));
}
我创建一个新的 vector
因为我不想修改原来的容器,但我也不想做无谓的复制。最简单的解决方案是创建一个指针 vector ,但问题是 *first
可能返回 const T&
(例如,来自 vector
)或 T
(例如,来自流)。
/* ??? */
因此 part 在概念上应该等同于 const T&
.我们真的不能这样做,因为 vector
s 不能包含不可分配的引用。我们不能使用 reference_wrapper<const T>
要么,因为它不能从临时构造。
我有什么选择?
最佳答案
你想要 /* ??? */
是一个可能拥有也可能不拥有 T
对象的类型,这取决于它是用临时 T
还是 const 构造的T&
。出于显而易见的原因,通常应避免此类类型。
一种替代方法是使用标签分派(dispatch)或 SFINAE 从两种可能的实现中选择一种,具体取决于 *first
返回的是引用类型还是非引用类型。
另一种选择是稍微缩小算法范围,使其只接受前向迭代器。这里保证您能够简单地存储迭代器本身并使用它们来比较指向的元素:
template <typename ForwardIt>
std::size_t unique_count(ForwardIt first, ForwardIt last) {
std::vector<ForwardIt> v;
for (auto i = first; i != last; ++i) {
v.push_back(i);
}
const auto pred = [](ForwardIt a, ForwardIt b) { return *a < *b; };
std::sort(v.begin(), v.end(), pred);
return std::distance(v.begin(), std::unique(v.begin(), v.end(), pred));
}
关于c++ - 对左值和右值的可分配引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38339471/