C 模板 - 具有模板类型的通用方法
C++ Templates - Having generic methods for templated types
我只是因为我想了解其他语言(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_cast
或 static_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));
}
可以说,有可能拥有能够存储的集合 任意指针重视实例?
不,它行不通。但是,至少有可能性:
-
如果您事先知道要在列表中使用的每种类型,则可以使用boost :: variant
-
您可以列出对象的指针列表(实际上是
void*
,也可以丢弃模板并将Value
作为基类),然后以某种方式(例如dynamic_cast
)将它们施放到某些特定的对象。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 类作用域的类型别名"using":[何时]方法中的用法可以先于类型别名?
- 调用具有未标识类型的类的方法
- 将复杂的非基元C++数据类型转换为 Erlang/Elixir 格式,以使用 NIF 导出方法
- 我的模板类方法返回错误类型?
- 在 C++ 中将非指定类型作为参数传递的最佳方法?
- QtQuick - qml:28:错误:未知方法返回类型:自定义类型
- 构造智能点数据类型以及普通数据类型的通用方法
- 如何在没有实例的情况下获取非静态方法的类型?
- C++方法是否可以根据传递给构造函数的参数具有不同的返回类型?
- 在自定义 std::vector-like 容器中处理指针和非指针模板类型的最佳方法是什么?
- 使用类型id运算符的最佳替代方法
- Java 调用 dll 字符串返回类型方法
- C++ 如何绑定和调用模板化类型方法
- 将返回类型推断为模板参数类型方法
- 返回true的模板化类型方法是在条件中进行优化的良好候选者