注意:我之前已经问过类似的问题,但是我没有发现它们有用或非常清楚。
第二个注释:对于此项目/作业的范围,我正在尝试避免使用第三方库,例如Boost。
我试图看看是否有一种方法可以让每个索引中的单个向量保持多个类型。例如,假设我有以下代码示例:
vector<something magical to hold various types> vec;
int x = 3;
string hi = "Hello World";
MyStruct s = {3, "Hi", 4.01};
vec.push_back(x);
vec.push_back(hi);
vec.push_back(s);
我听说vector<void*>
可以正常工作,但是随着内存分配变得棘手,如果插入某个索引的值更大,那么附近内存中的某些部分可能会无意中被覆盖比预期。
在我的实际应用程序中,我知道可以将可能的类型插入到向量中,但这些类型并非都来自同一个超类,并且无法保证所有这些类型将被推到矢量或按什么顺序。
有没有办法可以安全完成我在代码示例中演示的目标?
感谢您的时间。
答案 0 :(得分:19)
std::vector<T>
所持有的对象需要是同质类型。如果您需要将不同类型的对象放入一个向量中,您需要以某种方式擦除它们的类型并使它们看起来相似。您可以使用道德等值的boost::any
或boost::variant<...>
。 boost::any
的想法是封装一个类型层次结构,存储指向基础的指针,但指向模板化的派生。一个非常粗糙和不完整的轮廓看起来像这样:
#include <algorithm>
#include <iostream>
class any
{
private:
struct base {
virtual ~base() {}
virtual base* clone() const = 0;
};
template <typename T>
struct data: base {
data(T const& value): value_(value) {}
base* clone() const { return new data<T>(*this); }
T value_;
};
base* ptr_;
public:
template <typename T> any(T const& value): ptr_(new data<T>(value)) {}
any(any const& other): ptr_(other.ptr_->clone()) {}
any& operator= (any const& other) {
any(other).swap(*this);
return *this;
}
~any() { delete this->ptr_; }
void swap(any& other) { std::swap(this->ptr_, other.ptr_); }
template <typename T>
T& get() {
return dynamic_cast<data<T>&>(*this->ptr_).value_;
}
};
int main()
{
any a0(17);
any a1(3.14);
try { a0.get<double>(); } catch (...) {}
a0 = a1;
std::cout << a0.get<double>() << "\n";
}
答案 1 :(得分:8)
为了做到这一点,你肯定需要一个包装类来以某种方式隐藏对象的类型信息。
当你以前在将Type-B存储到其中时尝试获得Type-A时,让这个类抛出异常可能也是一件好事。
以下是我的一个项目中Holder类的一部分。你可以从这里开始。
注意:由于使用了不受限制的联合,这仅适用于C ++ 11。有关此内容的更多信息,请访问:What are Unrestricted Unions proposed in C++11?
class Holder {
public:
enum Type {
BOOL,
INT,
STRING,
// Other types you want to store into vector.
};
template<typename T>
Holder (Type type, T val);
~Holder () {
// You want to properly destroy
// union members below that have non-trivial constructors
}
operator bool () const {
if (type_ != BOOL) {
throw SomeException();
}
return impl_.bool_;
}
// Do the same for other operators
// Or maybe use templates?
private:
union Impl {
bool bool_;
int int_;
string string_;
Impl() { new(&string_) string; }
} impl_;
Type type_;
// Other stuff.
};
答案 2 :(得分:8)
根据建议,您可以使用各种形式的联合,变体等。根据您对存储对象的要求,外部多态可以完全按照您的意愿执行, 如果您可以定义所有必需的基类接口中的操作 。
这是一个例子,如果我们要做的就是将对象打印到控制台:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class any_type
{
public:
virtual ~any_type() {}
virtual void print() = 0;
};
template <class T>
class concrete_type : public any_type
{
public:
concrete_type(const T& value) : value_(value)
{}
virtual void print()
{
std::cout << value_ << '\n';
}
private:
T value_;
};
int main()
{
std::vector<std::unique_ptr<any_type>> v(2);
v[0].reset(new concrete_type<int>(99));
v[1].reset(new concrete_type<std::string>("Bottles of Beer"));
for(size_t x = 0; x < 2; ++x)
{
v[x]->print();
}
return 0;
}