C 模板 - 具有模板类型的通用方法

C++ Templates - Having generic methods for templated types

本文关键字:类型 方法 模板      更新时间:2023-10-16

我只是因为我想了解其他语言(Java)的特定差异而开始使用C 模板,而我达到了他们开始分歧的地步,但我没有得到我应该如何解决特定问题(或解决问题)。

假设我有一个通用值类,例如

template <class T>
class Value
{
  protected:
    T value;
  public:
    Value(Type type, T value) : type(type), value(value) {}
    void set(T value) { this->value = value; }
    T get() const { return this->value; }
    T clone() { return new Value<T>(type, value); }
    virtual string svalue() const = 0;
    const Type type;
};

和特定的子类型:

class Int : public Value<int>
{
  public:  
    Int(int value) : Value<int>(INT, value) { };
    virtual string svalue() const { ... }
  friend ostream& operator<<(ostream& os, const Int& v);
};

(我知道也可以使用template <>指定特定代码,但是由于我仍然需要使用它足以理解它,所以我暂时仅由自己的int类定义,这仅仅是typedef Value<int>结束)

是否可以说,可以将一个能够存储任意指针的集合来存储Value实例?无需指定通用类的特定混凝土类型。

据我了解,模板只是编译器分析使用模板的所有混凝土类型的编译时间问题,并为每个模板编译了相同方法的不同版本,因此我要做的似乎是不可能的(而在Java中,我可以使用通配符作为List<Value<?>>之类的东西)。我错了吗?

是否有一个共同的设计来解决此问题,或者我被迫丢弃模板来实现它?

#include <iostream>
#include <memory>
class Base 
{
    public: virtual void Print() = 0;
};
template<typename T>
class Derived : public Base
{
    T V;
public:
    void Print() { std::cout << V; }
    Derived(T v) : V(v) { }
};
int main()
{
    std::unique_ptr<Base> Ptr (new Derived<int>(5));
    Ptr->Print();
    return 0;
}

我认为这很不言而喻。

可以说,有可能拥有能够存储的集合 任意指针重视实例?

不,不是您想要的方式。这是不可能的:

template <class T>
class Value
{
// ...
};
vector<Value> my_values_;

这是不可能的,因为Value 不是类型 - 如果可以的话,它实际上只是一个蓝图和想法。除了哲学上的漫步,您无法存储想法,只能存储东西。 Value不是什么。

如果这是您想要的,则模板可能是工作的错误工具。小麦您可能真正追求的是抽象基类,其中基类(例如class Value)定义接口和子类(例如class Int : public Value)定义了混凝土类型。这样,您可以使用指针创建通用Value s的容器:

vector<Value*> my_values_;

或,最好使用智能指针:

vector<unique_ptr<Value>> my_values_;

可以通过公共基类的混合在C 中完成Java技术(请参阅Bartek的其他答案)和Type Erasure等技术。

C 版本实际上是值,在Java中无法完成。如果我没记错的话,可以用某些语言来编译到Java字节代码。

在Java中,您可以获得的唯一对象实际上更像是垃圾收集到C 中对象的指针。直接存储或提及的实际对象的实际实例是Verbotin,因为它阻碍了Java样式垃圾收集。

因此,Java中的Value<?>容器类似于指针的容器,即在C 中收集的所有Value类型的普通基类。然后访问每个实例,涉及java中的 dynamic_caststatic_cast

对于更多的Java Esque行为,用虚拟琐碎的破坏者,纯虚拟的通用方法为价值提供一个共同的基础,它们在所有情况下具有相同的签名,模板版本具有不同签名的事物,并产生shared_ptr S的工厂功能重视实例。

使用shared_ptr的容器对价值基础,并使用动态共享的PTR铸件(如果需要)来获取特定的接口。

现在,所有这些都意味着您的代码比没有所有结构的情况慢10至100倍,但是它仍然可能比等效的Java版本更快。如果您不需要,则可以选择不使用它。

我一直喜欢混淆问题并抛出一个不错的句法扭曲,尽管它仍然做同样的事情(使用公共基类)。唯一奇怪的位是Value<T>的基类是拼写的Value<>,可以在容器中使用(尽管不是直接,因为您需要使用点来避免切片):

#include <memory>
#include <vector>
template <typename T = void>
class Value;
template <>
class Value<void>
{
public:
    virtual ~Value() {}
};
template <typename T>
class Value
    : public Value<>
{
    T value_;
public:
    Value(T value): value_(value) {}
    // whatever
};
template <typename T>
std::unique_ptr<Value<T>> make_value(T value) {
    return std::unique_ptr<Value<T>>(new Value<T>(value));
}
int main()
{
    std::vector<std::unique_ptr<Value<>>> values;
    values.push_back(make_value(0));
    values.push_back(make_value(0.0));
    values.push_back(make_value(false));
}

可以说,有可能拥有能够存储的集合 任意指针重视实例?

不,它行不通。但是,至少有可能性:

  1. 如果您事先知道要在列表中使用的每种类型,则可以使用boost :: variant

  2. 您可以列出对象的指针列表(实际上是void*,也可以丢弃模板并将Value作为基类),然后以某种方式(例如dynamic_cast)将它们施放到某些特定的对象。

相关文章: