【问题标题】:C++ template subclass of a base w/o a template. How to extract template info thru base?没有模板的基础的 C++ 模板子类。如何通过基础提取模板信息?
【发布时间】:2018-04-02 05:48:58
【问题描述】:

更多我的玩具代码在这里:http://coliru.stacked-crooked.com/a/976e31bf360d7d15

struct DynamicInterface
{
    virtual ~DynamicInterface() = default;
    virtual size_t size() const = 0;
    virtual TypeCode type() const = 0;   

    // I wish I could do this , but template member functions cannot be virtual
    // due to compile time vs runtime requirements for templates vs virtual methods.
    // virtual template<typename T> std::vector<T>::iterator begin() = 0; 
    // virtual template<typename T> std::vector<T>::iterator end() = 0;
};

template<typename T>
class DynamicVector : public DynamicInterface
{
public:
    ~DynamicVector<T>() override = default;
    DynamicVector<T>(const std::vector<T>& vec, const TypeCode type) : vec_(vec), type_(type) {}
    size_t size() const override { return vec_.size(); }
    TypeCode type() const override { return type_; }
    T& operator[](size_t n) { return vec_[n]; }

    typename std::vector<T>::iterator begin() {return vec_.begin(); }
    typename std::vector<T>::iterator end() {return vec_.end(); }

    private:
        std::vector<T> vec_;
        TypeCode type_;
};

更具体地说,我有一个没有模板参数的轻量级界面。子类化是包含 std::vector 的模板类。

我希望我可以创建一个模板化的虚拟方法,以便通过指向接口的指针访问子类中封装的向量的迭代器。

如果这是我想做的事情,我怀疑我真的是 F$%@ed,但我想知道人们是否可以采取任何巧妙的技巧来解决这个问题或强迫编译器做一些接近的事情我想要的——C++ 有时真的需要杂技

【问题讨论】:

  • 假设你有一个DynamicInterface* ifc;。如果可能的话,你打算如何在不知道它是什么类型的情况下对 *ifc-&gt;begin() 这样的元素做任何有用的事情?
  • 知道你不能这样做,问问自己:“我想要解决的真正问题是什么?”语言特征只是达到目的的手段。很好地理解结尾可能会揭示您可以用来实现目标的其他语言功能。
  • @RSahu 正如在 coliru 的玩具代码中一样,我正在尝试制作一个类似 DataFrame 的类。实际上,我已经创建了一个包含由封装的 boost::variant 对象组成的单元格,并且运行良好。我的同事反驳说,列的类型不够安全,因为可以轻松地将单元格从 int 更改为 string 或其他任何东西,然后把事情搞砸——所以他推荐了这种方法来强化框架列中的类型(通过 boost: :对于空值是可选的)。然后我遇到了这些障碍,我认为我原来的方法现在更好了。
  • @FinanceGuyThatCantCode,我查看了您的代码,但没有任何聪明之处。希望别人可以。祝你好运。
  • @RSahu 感谢您的查找。我将主张在我的原始实现中检查 boost::variant 的运行时类型,以确保列类型的完整性,这会稍微减慢速度,但这仍然应该是我通过大量选项数据粉碎的一个重要的生产力增强器。 boost::variant 方法允许我以一些运行时类型检查为代价为我的许多函数提供适当的强类型返回类型 - 应该仍然比 Python 数据帧更快,并且可以用于更多的工业用例。跨度>

标签: c++ templates iterator


【解决方案1】:

我猜你想让你的接口非常通用,这样它就可以作为你所有子类的接口。如果您愿意将父级设为模板类,这仍然可以通过模板来实现(不确定这是否是您要寻找的)。

然后您可以使用子类的模板类型名来专门化继承。像这样:

#include <vector>
#include <cstdlib>
#include <iostream>
struct TypeCode {};
template <typename T> struct DynamicInterface {
    virtual ~DynamicInterface() = default;
    virtual size_t size() const = 0;
    virtual TypeCode type() const = 0;
    virtual typename std::vector<T>::iterator begin() = 0;
    virtual typename std::vector<T>::iterator end() = 0;
};
template <typename T> struct DynamicVector : public DynamicInterface<T> {
public:
    ~DynamicVector<T>() override = default;
    DynamicVector<T>(const std::vector<T>& vec, const TypeCode type) : vec_(vec), type_(type) {}
    size_t size() const override { return vec_.size(); }
    TypeCode type() const override { return type_; }
    T& operator[](size_t n) { return vec_[n]; }
    typename std::vector<T>::iterator begin() {return vec_.begin(); }
    typename std::vector<T>::iterator end() {return vec_.end(); }
private:
    std::vector<T> vec_;
    TypeCode type_;
};

int main() {
  TypeCode t;
  std::vector<int> v{1, 2};
  DynamicVector<int> d(v, t);
  std::cout << "begin: " << *d.begin() << "\n";
  std::cout << "end: " << *(d.end() - 1) << "\n";
}

这会给你输出:

begin: 1
end: 2

【讨论】:

    猜你喜欢
    • 2023-02-07
    • 1970-01-01
    • 2013-01-21
    • 2014-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多