我想将(动态)属性添加到C ++类中,该类可以是多种类型(例如float
,int
,bool
)。根据其值类型,应在界面中显示不同的控件。
为此,我使用SFINAE为type()
函数创建了一个简单的Property类:
#include <iostream>
#include <type_traits>
template <class T>
class Property
{
public:
enum Type {
Undefined = -1,
Int,
Float,
Bool,
};
explicit Property(const std::string& name) : name_(name) { }
const std::string& name() const { return name_; }
// specialization for floating point type() getter
template<class U = T,
typename std::enable_if<std::is_floating_point<U>::value>::type* = nullptr>
Type type() const {
return Type::Float;
}
// specialization for integer type() getter
template<class U = T,
typename std::enable_if<std::is_integral<U>::value>::type* = nullptr>
Type type() const {
return Type::Int;
}
// specialization for boolean type() getter
template<class U = T,
typename std::enable_if<std::is_same<U, bool>::value>::type* = nullptr>
Type type() const {
return Type::Bool;
}
private:
std::string name_;
T value_;
};
int main() {
// this works
auto fProp = new Property<float>("float property");
std::cout << fProp->type() << std::endl;
}
到目前为止,这种方法运作良好。现在,当我想在向量中存储其中的几个属性时,问题就出现了。为此,我创建了一个通用接口,并相应地更改了类:
#include <iostream>
#include <type_traits>
#include <vector>
class IProperty
{
// common interface for all typed Property<T>'s
public:
enum Type {
Undefined = -1,
Int,
Float,
Bool,
};
virtual const std::string& name() const = 0;
};
template <class T>
class Property : public IProperty
{
public:
explicit Property(const std::string& name) : name_(name) { }
const std::string& name() const { return name_; }
// specialization for floating point type() getter
template<class U = T,
typename std::enable_if<std::is_floating_point<U>::value>::type* = nullptr>
Type type() const {
return Type::Float;
}
// specialization for integer type() getter
template<class U = T,
typename std::enable_if<std::is_integral<U>::value>::type* = nullptr>
Type type() const {
return Type::Int;
}
// specialization for boolean type() getter
template<class U = T,
typename std::enable_if<std::is_same<U, bool>::value>::type* = nullptr>
Type type() const {
return Type::Bool;
}
private:
std::string name_;
T value_;
};
int main() {
// works
auto fProp = new Property<float>("float property");
std::cout << fProp->type() << std::endl;
std::vector<IProperty*> properties;
properties.push_back(fProp);
// error: 'class IProperty' has no member named 'type'
for (auto iprop : properties) {
std::cout << iprop->type() << std::endl;
}
}
如您所见,我无法调用type()
方法,因为它没有为IProperty
类定义。我尝试定义纯虚拟IProperty::type()
,但当然这不适用于模板化的派生类。
我有什么选择?
答案 0 :(得分:2)
专业化:
class IProperty
{
// common interface for all typed Property<T>'s
public:
enum Type {
Undefined = -1,
Int,
Float,
Bool,
};
virtual const std::string& name() const = 0;
virtual Type type() const { return Type::Undefined }
};
template <class T>
class Property : public IProperty
{
public:
explicit Property(const std::string& name) : name_(name) { }
const std::string& name() const override { return name_; }
Type type() const override;
private:
std::string name_;
T value_;
};
template <> Type Property<float>::type() const { return Type::Float;}
template <> Type Property<int>::type() const { return Type::Int;}
template <> Type Property<bool>::type() const { return Type::Bool;}
答案 1 :(得分:1)
class IProperty
{
public:
virtual Type getType() const=0;
enum {...}
};
template < class T > class PropertyByType : public IProperty
{
// implement here the differents type() method
// then :
virtual Type getType(){ return type<T>();}
}
template < class T >
class Property : public PropertyByType<T>
{
// ...
}
现在Property<T>*
可投放到IProperty*
,因此可以访问getType
方法
答案 2 :(得分:1)
扩展当前解决方案的一种简单方法是在基类中添加纯虚函数。要使其编译,请在派生类中添加一个额外的虚函数,该函数甚至可以与模板化变体具有相同的名称(但它可能会令人困惑):
class IProperty
{
// ...
virtual Type type() const = 0;
};
template <class T>
class Property : public IProperty
{
public:
// ...
// here type() is not a template, so it can be virtual
virtual Type type() const override
{
return type<T>();
}
};
现在,如果您使用类似
的内容auto fProp = new Property<float>("float property");
std::cout << fProp->type() << std::endl;
它实际上会调用新的接口函数而不是模板化的函数。
要直接调用模板,您必须明确说出:
auto fProp = new Property<float>("float property");
// note the <>
std::cout << fProp->type<>() << std::endl;
您实际上可能希望将内部(模板化)类型()函数声明为私有,因为它们不是接口(IPorperty)的一部分,因此不应公开。这将禁止调用fProp->type<>()
。