【发布时间】:2014-09-13 15:43:17
【问题描述】:
假设我有一个模板函数,它接受某种指针集合的 const 范围(或者更好的开始和结束迭代器)。 这个函数在内部构造了一个带有指针的 STL 容器来重组元素。
现在我也想将此函数用于 unique_ptr-collections。我不知何故需要修改模板参数或引入新的包装器或重载......但是如何? 是否有任何 C++11 模板魔术、STL 助手或 boost 助手? 以下是示例代码:
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
// Element Class
class Foo { };
// Take a range of elements, sort them internally by their addresses and print them in order
template <typename FooIterator>
void print_sorted_addresses(FooIterator beginFoos, FooIterator endFoos)
{
// Sort them
std::vector<const Foo*> elements(beginFoos, endFoos);
std::sort(elements.begin(), elements.end());
// Print them
for(const auto& e : elements)
std::cout << e << std::endl;
}
int main() {
std::vector<Foo*> raw_foos;
std::vector<std::unique_ptr<Foo>> unique_foos;
// Fill them
for(int i=0; i<10; i++) {
std::unique_ptr<Foo> foo(new Foo());
raw_foos.push_back(foo.get());
unique_foos.push_back(std::move(foo));
}
print_sorted_addresses(raw_foos.cbegin(), raw_foos.cend());
//print_sorted_Foos(unique_foos.cbegin(), unique_foos.cend()); // ERROR
return 0;
}
罪魁祸首似乎是原始指针和智能指针(尤其是unique_ptr)在将它们都转换为原始指针时的不统一行为。
这可以通过取消引用循环 à la std::addressof(*p) 来规避,但这只有在 p 不是 nullptr 时才具有明确定义的行为。
为了减少任何运行时检查,我使用了条件模板并提出了以下建议:
template<typename Ptr> using RawPtr = typename std::pointer_traits<Ptr>::element_type*;
// raw pointers like int**, const char*, ...
template<typename Ptr>
typename std::enable_if<std::is_pointer<Ptr>::value, RawPtr<Ptr>>::type make_raw(Ptr ptr) { return ptr; }
// smart pointers like unique_ptr, shared_ptr, ...
template<typename Ptr>
typename std::enable_if<!std::is_pointer<Ptr>::value, RawPtr<Ptr>>::type make_raw(Ptr& ptr) { return ptr.get(); }
这可以在@tclamb 的迭代器中使用,或者在 boost::transform_iterator 中使用,就像在@Praetorian 的回答中一样。但是,在智能指针实现的特定 get() 成员而不是使指针成为指针的 operator*-interface 上构建仍然感觉很奇怪。
【问题讨论】:
-
您不想打印
e而不是&e吗? -
我想使用自定义对象,但不想实现 operator
-
啊,你说得对……在基于范围的范围内,因为我已经有了指针……我会编辑。谢谢!
-
您也可以改用
vector<FooIterator>,然后注意排序是根据包含的值而不是FooIterator本身进行的。 -
@pmr。应该可以工作,但这意味着修改函数的内部逻辑。 (并且会为每个新的迭代器类型触发内部使用的容器的额外模板实例化......)
标签: c++ templates c++11 iterator unique-ptr