采取以下代码:

#include <string>
#include <iostream>

template <class T, class U>
class readonly
{
  friend U;
  private:
    T data;
    T operator=(const T& arg) {data = arg; return data;}
    T operator+=(const T& arg) {data = data + arg; return data;}
    T operator-=(const T& arg) {data = data - arg; return data;}
    T operator*=(const T& arg) {data = data * arg; return data;}
    T operator/=(const T& arg) {data = data / arg; return data;}
  public:
    operator const T&() const {return data;}
};

class myClass
{
  private:
    typedef readonly<int, myClass> RO_int;
    typedef readonly<std::string, myClass> RO_string;

  public:
    RO_int x;
    RO_string y;

    void f()
    {
      x = 55;
      y = "Howdy";
      std::cout << x << "\n\n";  // compiles fine
      std::cout << y << "\n\n";  // compile error
    }
};

我正在使用这些模板类来确保某些公共(public)变量xy在类外部为“只读”,但可以在类本身内进行修改。除了我试图显示字符串类型的变量y的最后一行之外,这段代码中的所有内容都可以正常编译。我不明白为什么我可以显示x而不显示y。如果需要重载<<运算符,为什么我必须对std::string而不是对int这样做呢?

最佳答案

首先,但不是您的问题,运算符(operator)应返回readonly&T&而不是T。不要那样破坏惯例。

现在是一个实际的答案。

这是因为operator<<使用的string是模板,并且模板功能在模式匹配时不考虑转换。接受<<int不是模板,因此它确实考虑了转换。

我们通常可以通过创建一个不会转换的operator<<来解决此问题:

只需添加

friend std::ostream& operator<<(std::ostream& os, readonly const& self)
{
  return os<<self.data;
}

设置为readonly类型,然后一切正常。这可以通过ADL找到。

我们可以通过使用模板中的第一个参数并检查<<是否有效以及第一个参数是否从std::ostream派生,或者类似地使用第二个参数,来使SFINAE等产品更出色。

关于c++ - 只读类变量(C++)和运算符重载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44894802/

10-16 05:31