我正在使用C ++编写属性系统(C ++ 11也可以),以便类可以向脚本系统提供数据。我想提供各种“类型”的属性,最简单的属性在内部保持其价值,如下所示:
// Simple Property
template<typename Value>
class Property {
public:
Value get() const;
void set(Value value);
private:
Value m_value;
}
对于大多数情况,这没关系,但有时,由于其他原因,该值已计算或必须在属性对象之外。对于这种情况,我想提供这样的模板:
// Complicated Property
template<
typename Value,
typename ValueOwner,
Value (ValueOwner::*Getter)(void) const,
void (ValueOwner::*Setter)(Value)
>
class Property {
// Stuff for calling the getter & setter
}
有没有办法让这两个模板共存而不重命名其中一个?我试过这个来专门化Getter / Setter模板:
// Complicated Property
// ...
// Simple Property
template<typename Value>
class Property<Value, void, nullptr, nullptr>;
但编译器并不喜欢这样,抱怨creating pointer to member function non-class type "const void"
。 Duh,当然void没有成员函数。
然后我尝试用足够的参数声明模板,然后专门化上面的模板,如下所示:
template<typename A, typename B, typename C, typename D>
class Property;
// Simple Property
// ...
// Complicated Property
// ...
但这也不起作用,因为Getter / Setter模板不希望typename作为第三和第四个参数,而是指向成员函数的指针。
接下来尝试:
// Complicated Property
// ...
// Simple Property
template<typename Value>
class Property<
Value,
Property<Value>,
&Property<Value>::get,
&Property<Value>::set
>;
编译失败,因为编译器现在没有模板参数中的Property<Value>
模板。
好吧,也许这一个:
// Complicated Property
// ...
template<typename Value>
struct PropertyDummy {
Value get() const;
void set(Value);
}
// Simple Property
template<typename Value>
class Property<
Value,
PropertyDummy<Value>,
&PropertyDummy<Value>::get,
&PropertyDummy<Value>::set
>;
为getter和setter模板参数产生了template argument involves template parameter(s)
。他们当然会这样做。
无论如何,将模板重命名为Property
和SimpleProperty
之类的内容对我而言非常有用。但我很好奇是否有解决方案,以便我可以写两个
Property<int> simpleProperty;
Property<int, MyClass, &MyClass::get, &MyClass::set> complicatedProperty;
让编译器找出我的意思。
答案 0 :(得分:3)
是否需要在编译时指定getter和setter?您可以使用Value
和ValueOwner
模板参数获取类型:
template<
typename Value,
typename ValueOwner,
>
class Property {
public:
typedef Value (ValueOwner::*Getter)(void) const;
typedef void (ValueOwner::*Setter)(Value);
Property(Getter getter, Setter setter)
: getter(getter), setter(setter) {}
// ...
private:
Getter getter;
Setter setter;
};
然后将适当的函数指针传递给构造函数:
Property<int, MyClass> complicatedProperty(&MyClass::get, &MyClass::set);
答案 1 :(得分:3)
但我很好奇是否有解决方案以便[...]
是的,有。
您可以使用以下方法。首先,在客户端不应该处理的某个命名空间中创建一个虚拟类模板:
namespace detail
{
template<typename T>
struct dummy
{
T get() const { return T(); }
void set(T) { }
};
}
然后,定义以下主模板:
#include <type_traits>
// Simple Property
template<typename Value,
typename ValueOwner = detail::dummy<Value>,
Value (ValueOwner::*Getter)(void) const = &ValueOwner::get,
void (ValueOwner::*Setter)(Value) = &ValueOwner::set,
bool = std::is_same<ValueOwner, detail::dummy<Value>>::value
>
class Property {
public:
Value get() const;
void set(Value value);
private:
Value m_value;
};
最后一个虚拟模板参数的值取决于dummy<Value>
是否作为第二个参数传递(客户端当然不应该使用dummy
类模板)。
然后,当最后一个参数为false
(意味着为第二个模板参数提供了一些参数)时,您可以专门设置模板:
// Complicated Property
template<
typename Value,
typename ValueOwner,
Value (ValueOwner::*Getter)(void) const,
void (ValueOwner::*Setter)(Value)
>
class Property<Value, ValueOwner, Getter, Setter, false>
{
// Stuff for calling the getter & setter
};
最后,你可以使用你提出的两个声明:
struct MyClass
{
int get() const { return 42; }
void set(int) { }
};
int main()
{
Property<int> simpleProperty;
Property<int, MyClass, &MyClass::get, &MyClass::set> complicatedProperty;
}