我有兴趣为C ++实现类似Java集合的环境。 我知道这不是一个好主意等等,但我不想在以后使用它,但只是学习如何做一些高级OOP。
我的问题是我想要一个带有纯虚函数的基类模板collection<T>
。其中一个函数应为map()
,其中std::function<R(T)>
为map()
。由于collection<R>
应该是虚拟的,我不知道我应该使用哪种返回类型。 map()
是不可能的,因为成员函数模板不能是虚拟的。
如何为collection<T>
界面添加此类strategy:
type: "Docker"
dockerStrategy:
noCache: true
成员函数?
答案 0 :(得分:7)
如何为
map
界面添加此类collection<T>
成员函数?
简短的回答是:你不是。如果我有一些collection<int>
并且我想map
std::to_string
,我需要生成一个collection<std::string>
。但vector_collection<int>
需要生成vector_collection<std::string>
和list_collection<int>
需要生成list_collection<std::string>
- 因此类型转换本身需要virtual
。但是你不能拥有virtual
个成员函数模板,因此无法表达这一点。
为了实现这一点,您必须为您放入容器中的所有对象设置一个公共基本类型,然后才能拥有一个可以在其间投射的公共外观。也就是说,您实际上只有collection<unique_ptr<Object>>
map
只是为您提供了不同的collection<unique_ptr<Object>>
,而您只是map
将collection_facade<int, collection<unique_ptr<Object>>>
改为collection_facade<std::string, collection<unique_ptr<Object>>>
。通过大量工作并完全无视性能和类型安全性,您可以实现目标。
这是模板的优势。如果我想为map
之类的内容写vector
,我可以写下:
template <class T, class A, class F, class R = std::result_of_t<F(T)>>
std::vector<R, A> map(std::vector<T, A> const& v, F f) {
std::vector<R, A> mapped;
mapped.reserve(v.size());
for (T const& elem : v) {
mapped.push_back(f(elem));
}
return mapped;
}
或:
template <class T, class A, class F, class R = std::result_of_t<F(T)>>
std::vector<R, A> map(std::vector<T, A> const& v, F f) {
return std::vector<R, A>(
boost::make_transform_iterator(v.begin(), f),
boost::make_transform_iterator(v.end(), f)
);
}
我必须分别为每个容器实现map()
- 但无论如何我都必须这样做。而现在我没有放弃任何东西。此外,您经常编写与运行时容器无关的算法吗?
答案 1 :(得分:0)
实施map
作为外部模板功能。
例如,您可以分两个阶段分解map
,内部虚拟生产者和外部模板化消费者。
template<typename T> struct Collection {
// virtual T next(); // Java way
// C++ way
// In simplest cases you can rely on iterator pairs.
struct const_iterator {
T const &operator*() const;
const_iterator &operator++();
}
virtual const_iterator begin() const;
virtual const_iterator end() const;
};
template<typename R, typename T> Collection<R> map(
Collection<T> const &coll, std::function<R(T)> const &f);
要实现本质上复杂的容器和monadic组合,您甚至可以拒绝begin()
和end()
并编写显式(部分)模板专业化。