4

受此答案的启发,我将以下解决方案用于只读成员变量:

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:我创建了一个单元测试,消除了所有其他的东西。我已经没有性能损失了,太好了,毕竟没有问题。谢谢您的帮助!而且我已经修复了构造函数,很好的调用。

4

7 回答 7

5

您的优化是无用的,将产生完全相同的代码。所有这些readonly都是微不足道的,并且将被内联,消除了使用原始 T 可能产生的任何开销。因此,解决方案是不修复不存在的问题,readonly<int, A>而不管这是否是调试构建,都只使用。

正如@MooingDuck 所指出的,您应该将构造函数更改为使用 init 列表(并且可能也使其显式)。

于 2012-05-24T18:56:13.030 回答
3

使用辅助元函数:

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;
于 2012-05-24T18:56:03.563 回答
2

你的方法对我来说是一个很大的问题:它可以在 DEBUG 和 RELEASE 模式下生成不同的代码。在这里我考虑的不是性能,而是语义。如果优化器无法生成等效的二进制文件,我会感到惊讶。

在 DEBUG 版本中,每当使用元素时都需要用户定义的转换,但在 RELEASE 中,该转换被丢弃,这反过来可以启用不同的用户定义的转换,并导致在成员属性时选择不同的重载作为参数传递给函数。

虽然可能不是一种常见的情况,但如果您确实遇到了它,您将在尝试确定为什么应用程序在 RELEASE 中始终失败但您无法使用您的 DEBUG 版本对其进行调试时会遇到很多调试痛苦......

于 2012-05-24T19:26:37.887 回答
1

const 修饰符没有性能方面的问题。给定一个好的优化器,你的调试和发布版本将产生相同的代码。

于 2012-05-24T18:56:45.560 回答
0

这是一个稍微不同的看法。如果您想要一个只读变量但不希望客户端必须更改他们访问它的方式,请尝试使用这个模板类:

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!请记住,您还需要添加按位和一元运算符!这只是一个让您入门的示例

于 2014-04-01T01:10:39.630 回答
0

我更喜欢这两种解决方案。

第一个使用privateinline

class A
{
    public:
        inline int GetI();
        {
            return i;
        }

    private:
        int i;
}

第二个使用constconst_cast

class A
{
    public:
        const int I;

        void SetI(int newI)
        {
            //Verify newI or something.

            const_cast<int>(I) = newI;
        }
}
于 2016-06-11T08:35:56.953 回答
-2

我不是 100% 确定,但看起来不可能用模板来做到这一点。因为模板无法读取预处理器变量。为了使您的代码更具可读性,您可以定义像 READONLY_INT 这样的宏并在其他 .h 文件中声明它。

于 2012-05-24T18:58:27.183 回答