首页 文章

在C中为非const模板化版本的朋友

提问于
浏览
1

考虑以下代码:

template<class T>
class Me {
private:
    T* data;
    size_t size;

    friend class Me<?????>;
public:
    Me(size_t s) : data(new T[s]), size(s) {}
    virtual ~Me() { delete [] data; }

    Me<T> operator= (const Me<T const>& rhs) {
        for(size_t i = 0; i < size; ++i)
            data[i] = rhs.data[i]; // Gives compile error "data is a private member of Me<XX const>"
    }
}

无视这是一个非常人为的例子,访问类的一个版本的私有数据成员的正确方法是什么,只有 T 的常量?如果它是另一种方式,我可以简单地做: friend class Me<T const>;

我不希望在我的实际代码中公开一种访问更广泛世界的内部数据指针(甚至通过getter)的方法 . 此外,我在这里没有做任何违反const正确性的事情,因为我永远不会修改等式的右边 .

也许这完全是错误的方式,但这似乎是一个非常合理的事情 .

创建免费功能会更好吗?例如 .

template<class T>
Me<T> operator= (const Me<T>& lhs, const Me<T const>& rhs) {...}

第二种方法编译很好,但给了我一个链接(未定义的符号)错误,我仍在追查 .

3 回答

  • 4

    访问类的一个版本的私有数据成员的正确方法只有T的常量不同?

    关于什么

    friend class Me<std::remove_const_t<T>>;
    

    在您的情况下, T (没有 const )版本必须访问 T const 版本的私有数据 .

    所以你必须交到 T (没有 const )版本的朋友 .

    关闭主题建议:您标记了C 17,因此您可以使用智能指针 .

    使用它们!

    默认的复制构造函数和 Me 的默认 operator=() 是非常非常危险的(几乎可以保证相同的分配内存的两倍) .

  • 1

    您需要定义类的赋值运算符,并且在 Me<T const> 上工作的模板运算符也可以为no const版本提供友谊:

    template<class T>
    class Me {
    private:
        friend class Me<std::remove_const_t<T>>;
    public:
    
        Me<T>& operator= (const Me<T>& rhs) {
            // ...
            return *this;
        }
    
        template <class U, std::enable_if_t<std::is_same_v<U, T const>, bool> = true>
        Me<T>& operator=(Me<U> const& rhs) {
            // ...
            return *this;
        }
    };
    
    Me<int> r;
    Me<int const> l;
    r = l;
    
  • 2

    我认为这比接受的答案稍微好一些,因为它不需要重载赋值运算符 . 此外,此版本将禁用 const T 类型的赋值运算符 . (因为你可能不想复制它们) .

    #include <type_traits>
    template<class T>
    class Me {
    private:
        friend class Me<std::remove_const_t<T>>;
    public:
    
        template <class U>
        std::enable_if_t<std::is_same<std::remove_const_t<U>, T>::value, Me<T>&>
        operator=(Me<U> const& rhs) {
            return *this;
        }
    };
    
    int main() {
    
        Me<int> r;
        Me<int const> l;
    
        r = l;
        r = r;
        l = l;
    
        l = r; //will cause compilation failure.
    }
    

    此版本也将支持 const T 类型的赋值运算符 .

    template <class U>
        std::enable_if_t<std::is_same<std::remove_const_t<U>, std::remove_const_t<T>>::value, Me<T>&>
        operator=(Me<U> const& rhs) {
            return *this;
        }
    

相关问题