请使用以下代码:
#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
}
};
我使用这些模板类来确保某些公共变量x
和y
是&#34;只读&#34;在类之外,但可以在类本身内进行修改。除了我试图显示字符串类型的变量y的最后一行之外,此代码中的所有内容都编译得很好。我不明白为什么我能够显示x
而不是y
。如果我需要重载<<
运算符,为什么我必须为std::string
而不是int
执行此操作?
答案 0 :(得分:3)
首先,但不是您的问题,您的运营商应该返回readonly&
或T&
而不是T
。不要像那样违反惯例。
现在给出一个实际答案。
这是因为operator<<
使用string
是模板,模板函数在模式匹配时不考虑转换。获取<<
的{{1}}不是模板,因此会考虑转化。
我们可以通过创建一个无法转换的int
来解决此问题:
只需添加
operator<<
到你的friend std::ostream& operator<<(std::ostream& os, readonly const& self)
{
return os<<self.data;
}
类型,事情应该有效。这将通过ADL找到。
我们可以通过模板获取第一个参数并检查readonly
是否有效以及第一个参数是从<<
派生,还是类似地针对第二个参数,使SFINAE之类的版本变得更加漂亮。