在没有模板 class 的 class 中声明一个模板向量成员?
declare a template vector member in a class without template the class?
我有一些 class 应该填充值,
但我不知道值的类型。
澄清一下,class 实例中的每个向量都填充了相同的值类型,
但是 SomeClass 的一个实例可以有 vector<int>
和另一个 vector<string>
等等。
如何将向量声明为模板,而不是 class 本身的模板?
template<typename T>
struct tvector {
typedef std::vector< std::vector<T> > type;
};
class SomeClass {
public:
int _someField;
tvector<T> _fieldValues; // this line fails to compile
};
提前致谢
有几种不同的方法可以剪掉这头野兽。这主要取决于您希望如何访问此向量以及您如何在运行时确定其确切类型。
std::变体
一个变量可以存储一组预先确定的类型。如果您有许多不同的类型,它很有效但也很麻烦,因为您必须通过某种类型检查来收集每次访问。
class SomeClass {
public:
using variant_type = std::variant<
std::vector<int>, std::vector<double> >;
int _someField;
variant_type _fieldValues;
void print(std::ostream& stream) const
{
switch(_fieldValues.index()) {
case 0:
for(int i: std::get<0>(_fieldValues))
stream << i << ' ';
break;
case 1:
for(double i: std::get<1>(_fieldValues))
stream << i << ' ';
break;
default: break;
}
}
};
std::任意
Any 几乎可以容纳任何类型。提高了可扩展性,但使使用这些值变得困难。
class SomeClass {
public:
int _someField;
std::any _fieldValues;
void print(std::ostream& stream) const
{
if(_fieldValues.type() == typeid(std::vector<int>))
for(int i: std::any_cast<std::vector<int>>(_fieldValues))
stream << i << ' ';
else if(_fieldValues.type() == typeid(std::vector<double>))
for(double i: std::any_cast<std::vector<double>>(_fieldValues))
stream << i << ' ';
else
throw std::runtime_error("Not implemented");
}
};
子类化
最优雅的方式(恕我直言)是使用模板化子类。像这样:
class SomeClass {
public:
int _someField;
virtual ~SomeClass() = default;
virtual void print(std::ostream& stream) const = 0;
};
template<class T>
SomeClassT: public SomeClass
{
std::vector<T> _fieldValues;
public:
virtual void print(std::ostream& stream) const
{
for(const T& i: _fieldValues)
stream << i << ' ';
}
};
或者,如果您不想公开该部分,请将其设为私有成员。
class SomeClassHelper {
public:
virtual ~SomeClassHelper() = default;
virtual void print(std::ostream& stream) const = 0;
};
template<class T>
SomeClassHelperT: public SomeClassHelper
{
std::vector<T> _fieldValues;
public:
virtual void print(std::ostream& stream) const
{
for(const T& i: _fieldValues)
stream << i << ' ';
}
};
class SomeClass {
public:
int _someField;
private:
std::unique_ptr<SomeClassHelper> helper;
public:
void print(std::ostream& stream) const
{ return helper->print(stream); }
};
我有一些 class 应该填充值, 但我不知道值的类型。
澄清一下,class 实例中的每个向量都填充了相同的值类型,
但是 SomeClass 的一个实例可以有 vector<int>
和另一个 vector<string>
等等。
如何将向量声明为模板,而不是 class 本身的模板?
template<typename T>
struct tvector {
typedef std::vector< std::vector<T> > type;
};
class SomeClass {
public:
int _someField;
tvector<T> _fieldValues; // this line fails to compile
};
提前致谢
有几种不同的方法可以剪掉这头野兽。这主要取决于您希望如何访问此向量以及您如何在运行时确定其确切类型。
std::变体
一个变量可以存储一组预先确定的类型。如果您有许多不同的类型,它很有效但也很麻烦,因为您必须通过某种类型检查来收集每次访问。
class SomeClass {
public:
using variant_type = std::variant<
std::vector<int>, std::vector<double> >;
int _someField;
variant_type _fieldValues;
void print(std::ostream& stream) const
{
switch(_fieldValues.index()) {
case 0:
for(int i: std::get<0>(_fieldValues))
stream << i << ' ';
break;
case 1:
for(double i: std::get<1>(_fieldValues))
stream << i << ' ';
break;
default: break;
}
}
};
std::任意
Any 几乎可以容纳任何类型。提高了可扩展性,但使使用这些值变得困难。
class SomeClass {
public:
int _someField;
std::any _fieldValues;
void print(std::ostream& stream) const
{
if(_fieldValues.type() == typeid(std::vector<int>))
for(int i: std::any_cast<std::vector<int>>(_fieldValues))
stream << i << ' ';
else if(_fieldValues.type() == typeid(std::vector<double>))
for(double i: std::any_cast<std::vector<double>>(_fieldValues))
stream << i << ' ';
else
throw std::runtime_error("Not implemented");
}
};
子类化
最优雅的方式(恕我直言)是使用模板化子类。像这样:
class SomeClass {
public:
int _someField;
virtual ~SomeClass() = default;
virtual void print(std::ostream& stream) const = 0;
};
template<class T>
SomeClassT: public SomeClass
{
std::vector<T> _fieldValues;
public:
virtual void print(std::ostream& stream) const
{
for(const T& i: _fieldValues)
stream << i << ' ';
}
};
或者,如果您不想公开该部分,请将其设为私有成员。
class SomeClassHelper {
public:
virtual ~SomeClassHelper() = default;
virtual void print(std::ostream& stream) const = 0;
};
template<class T>
SomeClassHelperT: public SomeClassHelper
{
std::vector<T> _fieldValues;
public:
virtual void print(std::ostream& stream) const
{
for(const T& i: _fieldValues)
stream << i << ' ';
}
};
class SomeClass {
public:
int _someField;
private:
std::unique_ptr<SomeClassHelper> helper;
public:
void print(std::ostream& stream) const
{ return helper->print(stream); }
};