【问题标题】:Interface with template member function与模板成员函数的接口
【发布时间】:2016-09-11 05:26:33
【问题描述】:

我有兴趣为 C++ 实现一个类似 Java 集合的环境。 我知道这不是一个好主意等等,但我真的不想以后再使用它,只是学习如何做一些高级 OOP。

我的问题是我想要一个带有纯虚函数的基类模板collection<T>。其中一个函数应该是map(),它采用std::function<R(T)>。因为map() 应该是虚拟的,所以我不知道应该使用哪种返回类型。 collection<R> 是不可能的,因为成员函数模板不能是虚拟的。

如何为我的collection<T> 接口添加这样的map() 成员函数?

【问题讨论】:

  • c++ 标准容器有什么问题?
  • @πάντα ῥεῖ OP 正在尝试这样做是为了学习目的。
  • 没什么,我只是想知道如何为教育目的实现这样的东西
  • 您必须在 C++ 中实现类型擦除。祝你好运。
  • C++ 中已经有类型擦除的例子。见 std:shared_ptr 和 std::function

标签: c++ oop templates functional-programming


【解决方案1】:

如何为我的collection<T> 接口添加这样的map 成员函数?

简短的回答是:你不知道。如果我有一些collection<int> 并且我想在上面添加map std::to_string,我需要生成一个collection<std::string>。但是vector_collection<int> 需要生成vector_collection<std::string>list_collection<int> 需要生成list_collection<std::string>——因此类型转换本身需要virtualized。但是你不能有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>>>。通过大量的工作和完全无视性能和类型安全,你可以做到。


这就是模板的优势。如果我想为vector 之类的东西写map,我可以这样写:

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() - 但无论如何我都必须这样做。现在我不会放弃任何东西。此外,您多久编写一次与运行时容器无关的算法?

【讨论】:

  • allocator也可以反弹。
【解决方案2】:

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);

要实现本质上复杂的容器和一元组合,您甚至可以拒绝 begin()end() 并编写显式(部分)模板特化。

【讨论】:

    猜你喜欢
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-11
    相关资源
    最近更新 更多