据我所知,这似乎是不可能直接的。使const成员使每个人都成为const。我想有一个只读属性,但我想避免典型的“getter”。我喜欢const public,mutable private。这在C ++中是否可行?
目前我能想到的只是模板和friend
的一些技巧。我现在正在调查这个。
可能看起来像是一个愚蠢的问题,但我之前对这里的答案感到惊讶。
答案 0 :(得分:3)
一个可能的解决方案可以基于一个内部类,其中外部类是朋友,如下所示:
struct S {
template<typename T>
class Prop {
friend struct S;
T t;
void operator=(T val) { t = val; }
public:
operator const T &() const { return t; }
};
void f() {
prop = 42;
}
Prop<int> prop;
};
int main() {
S s;
int i = s.prop;
//s.prop = 0;
s.f();
return i, 0;
}
如示例所示,类S
可以在其成员函数中修改属性(请参阅S::f
)。另一方面,属性不能以任何其他方式修改,但仍然通过给定的运算符读取,该运算符返回对实际变量的const引用。
答案 1 :(得分:3)
似乎还有另一个更明显的解决方案:使用一个公共const引用成员,指向私有的,可变的成员。 live code here
#include <iostream>
struct S {
private:
int member;
public:
const int& prop;
S() : member{42}, prop{member} {}
S(const S& s) : member{s.member}, prop{member} {}
S(S&& s) : member(s.member), prop{member} {}
S& operator=(const S& s) { member = s.member; return *this; }
S& operator=(S&& s) { member = s.member; return *this; }
void f() { member = 32; }
};
int main() {
using namespace std;
S s;
int i = s.prop;
cout << i << endl;
cout << s.prop << endl;
S s2{s};
// s.prop = 32; // ERROR: does not compile
s.f();
cout << s.prop << endl;
cout << s2.prop << endl;
s2.f();
S s3 = move(s2);
cout << s3.prop << endl;
S s4;
cout << s4.prop << endl;
s4 = s3;
cout << s4.prop << endl;
s4 = S{};
cout << s4.prop << endl;
}
答案 2 :(得分:0)
我喜欢@skypjack的答案,但是会以某种方式写出来:
#include <iostream>
template <class Parent, class Value> class ROMember {
friend Parent;
Value v_;
inline ROMember(Value const &v) : v_{v} {}
inline ROMember(Value &&v) : v_{std::move(v)} {}
inline Value &operator=(Value const &v) {
v_ = v;
return v_;
}
inline Value &operator=(Value &&v) {
v_ = std::move(v);
return v_;
}
inline operator Value& () & {
return v_;
}
inline operator Value const & () const & {
return v_;
}
inline operator Value&& () && {
return std::move(v_);
}
public:
inline Value const &operator()() const { return v_; }
};
class S {
template <class T> using member_t = ROMember<S, T>;
public:
member_t<int> val = 0;
void f() { val = 1; }
};
int main() {
S s;
std::cout << s.val() << "\n";
s.f();
std::cout << s.val() << "\n";
return 0;
}
一些enable_if
缺少真正的核心通用,但精神是让它可以重复使用并让呼叫看起来像吸气剂。
这确实是一个带有friend
的技巧。
答案 3 :(得分:-1)
您可以使用奇怪的重复模板模式,并在属性类中与超类成为朋友,如下所示:
#include <utility>
#include <cassert>
template<typename Super, typename T>
class property {
friend Super;
protected:
T& operator=(const T& val)
{ value = val; return value; }
T& operator=(T&& val)
{ value = val; return value; }
operator T && () &&
{ return std::move(value); }
public:
operator T const& () const&
{ return value; }
private:
T value;
};
struct wrap {
wrap() {
// Assign OK
prop1 = 5; // This is legal since we are friends
prop2 = 10;
prop3 = 15;
// Move OK
prop2 = std::move(prop1);
assert(prop1 == 5 && prop2 == 5);
// Swap OK
std::swap(prop2, prop3);
assert(prop2 == 15 && prop3 == 5);
}
property<wrap, int> prop1;
property<wrap, int> prop2;
property<wrap, int> prop3;
};
int foo() {
wrap w{};
w.prop1 = 5; // This is illegal since operator= is protected
return w.prop1; // But this is perfectly legal
}