这个答案的启发,我正在对只读成员变量使用以下解决方案:
template <class T, class OWNER>
class readonly
{
friend OWNER;
public:
explicit readonly(const T &t) : m_t(t)
{
}
~readonly()
{
}
operator const T&() const
{
return m_t;
}
private:
T& operator =(const T &t)
{
m_t = t;
return m_t;
}
T m_t;
};
效果很好,为了稍微优化性能,我像这样使用它:
class A
{
public:
A()
{
}
~A()
{
}
#ifdef _DEBUG // DON'T USE THIS SWITCH, SEE ANSWERS BELOW!
readonly<int, A> m_x, m_y;
#else
int m_x, m_y;
#endif
};
但是,我很想消除预编译器开关,该开关检查我们是否正在进行调试或发布构建......有没有人看到使用宏或聪明的模板技巧的解决方案?
编辑:我已经在循环中检查了性能,它使用VS2010产生约15~20%的开销。它不会导致相同的代码,启用自动内联。
编辑#2:我创建了一个单元测试,消除了所有其他内容。我不再有性能损失了,这么大,毕竟没有问题。感谢您的帮助!我已经修复了构造函数,很好的调用。
您的优化是无用的,并且会产生完全相同的代码。所有readonly
都是微不足道的,并且将被内联,从而消除了使用原始 T 可能产生的任何开销。因此,解决方案是不修复不存在的问题,而只使用readonly<int, A>
,无论这是否是调试版本。
正如@MooingDuck所指出的,你应该将构造函数更改为使用 init list(并且可能也使其显式)。
使用辅助元函数:
template< typename T, typename Owner >
struct make_read_only
{
#ifdef _DEBUG
typedef readonly< T, Owner > type;
#else
typedef T type;
#endif
};
并将您的会员声明更改为:
make_read_only< int, A >::type;
你的方法对我来说是一个很大的问题:它可以在调试和发布模式下生成不同的代码。在这里,我考虑的不是性能,而是语义。如果优化器无法生成等效的二进制文件,我会感到惊讶。
在 DEBUG 版本中,每当使用该元素时都需要用户定义的转换,但在 RELEASE 中,该转换被丢弃,这反过来又允许使用不同的用户定义转换,并导致在将成员属性作为参数传递给函数时选取不同的重载。
虽然可能不是一个常见的情况,但如果你确实遇到了它,你会有很多调试痛苦,试图确定为什么应用程序在 RELEASE 中总是失败,但你不能用你的 DEBUG 版本调试它......
const 修饰符没有性能方面。如果有一个好的优化器,你的调试和发布版本将产生相同的代码。
这是一个稍微不同的看法。如果你想要一个只读变量,但不希望客户端必须更改他们访问它的方式,请尝试以下模板化类:
template<typename MemberOfWhichClass, typename primative>
class ReadOnly {
friend MemberOfWhichClass;
public:
inline operator primative() const { return x; }
template<typename number> inline bool operator==(const number& y) const { return x == y; }
template<typename number> inline number operator+ (const number& y) const { return x + y; }
template<typename number> inline number operator- (const number& y) const { return x - y; }
template<typename number> inline number operator* (const number& y) const { return x * y; }
template<typename number> inline number operator/ (const number& y) const { return x / y; }
template<typename number> inline number operator<<(const number& y) const { return x <<y; }
template<typename number> inline number operator>>(const number& y) const { return x >> y; }
template<typename number> inline number operator^ (const number& y) const { return x ^ y; }
template<typename number> inline number operator| (const number& y) const { return x | y; }
template<typename number> inline number operator& (const number& y) const { return x & y; }
template<typename number> inline number operator&&(const number& y) const { return x &&y; }
template<typename number> inline number operator||(const number& y) const { return x ||y; }
template<typename number> inline number operator~() const { return ~x; }
protected:
template<typename number> inline number operator= (const number& y) { return x = y; }
template<typename number> inline number operator+=(const number& y) { return x += y; }
template<typename number> inline number operator-=(const number& y) { return x -= y; }
template<typename number> inline number operator*=(const number& y) { return x *= y; }
template<typename number> inline number operator/=(const number& y) { return x /= y; }
template<typename number> inline number operator&=(const number& y) { return x &= y; }
template<typename number> inline number operator|=(const number& y) { return x |= y; }
primative x;
};
使用示例:
class Foo {
public:
ReadOnly<Foo, int> x;
};
现在您可以访问 Foo.x,但无法更改 Foo.x!请记住,您还需要添加按位运算符和一元运算符!这只是帮助您入门的示例
我更喜欢这两个解决方案。
第一个使用私有和内联:
class A
{
public:
inline int GetI();
{
return i;
}
private:
int i;
}
第二个使用常量和const_cast:
class A
{
public:
const int I;
void SetI(int newI)
{
//Verify newI or something.
const_cast<int>(I) = newI;
}
}
我不是 100% 确定,但看起来不可能用模板做到这一点。因为模板无法读取预处理器变量。为了使您的代码更具可读性,您可以定义像 READONLY_INT 这样的宏,并在其他 .h 文件中声明它。