C++ 重载 [] 与转换
C++ overload[] with transformation
我有一个表示布尔值向量的 C 数据结构;由于我无法控制的原因,布尔值在内部存储为整数,具有两个表示真和假的神奇值(不是 0 和 1 ...)。我已经创建了一个 C++ class 包装这个 C 结构,它工作得很好。我已经将 set()
和 get()
方法实现为:
void Class::set(size_t index , bool value) {
if (value)
c_ptr[index] = SPECIAL_TRUE_VALUE;
else
c_ptr[index] = SPECIAL_FALSE_VALUE;
}
这没问题;但理想情况下我想重载 operator[],但我不清楚 how/if 我能做到吗 - 由于 bool 和整数值之间的特殊转换?
struct pseudo_reference {
operator bool()const&&{
return c->get(index);
}
pseudo_reference operator=(bool b)&&{
c->set(index, b);
return {c,index};
}
// sometimes having named functions is useful:
bool get() const&& {
return std::move(*this);
}
void set(bool b)&& {
std::move(*this) = b;
}
pseudo_reference()=delete;
private:
Class* c;
size_t index;
pseudo_reference(pseudo_reference&&o)=default; // not exposed
pseudo_reference(Class* pc, size_t i):c(pc),index(i){}
friend class Class;
};
在Class
中:
pseudo_reference operator[](size_t i){
return {this, i};
}
bool operator[](size_t i)const{
return c_ptr[index] == SPECIAL_TRUE_VALUE;
}
我存储了一个指针和一个索引,所以我避免在我的 pseudo_reference
中重新实现 get
/set
的逻辑。这样的 pseudo_references
可能是短暂的,因此大小优化可能并不重要。
我阻止了所有非右值操作以阻止存储 pseudo_reference
。您可以相对无害地对非右值操作进行限制,但根据我的经验,pseudo_references
值的行为类似于引用,因此最好不要持久化它们。
有人仍然可以通过 auto&& x = c[33];
存储 pseudo_reference
,但如果不 move
将无法使用它。希望这能抓住 大多数 容易出错的用法。 auto x = c[33];
不行。
您可以 return 包装器助手 class 为您处理分配。
struct WrapMe {
c_ptr_T &value;
WrapMe(c_ptr_T &_value) : value(_value) {}
// handles assignment of bool values
WrapMe & operator=(const bool b) {
value = (b) ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE;
return *this;
}
// handles cast to bool
operator bool() const { return value == SPECIAL_TRUE_VALUE; }
};
class Class {
WrapMe operator[](const int idx) { return WrapMe(c_ptr[idx]); }
// ...
};
要实现 operator[]()
,您需要 return 一个代理对象,当它出现在 =
的左侧时执行实际分配:
struct proxy {
proxy& operator=( bool value ) {
c_.c_ptr[ index_ ] = value ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE;
return *this;
}
operator bool() const { // for when it's just used normally, not =
return c_ptr[ index ] == SPECIAL_TRUE_VALUE;
}
private:
Class &c_;
size_t const index_;
proxy( Class &c, size_t index ) : c_( c ), index_( index ) { }
friend class Class;
}
class Class {
public:
proxy operator[]( size_t index ) {
return proxy( *this, index );
}
bool operator[]( size_t index ) const { // read-only access is easy
return c_ptr[ index ] == SPECIAL_TRUE_VALUE;
}
// ...
};
或者类似的东西。
我有一个表示布尔值向量的 C 数据结构;由于我无法控制的原因,布尔值在内部存储为整数,具有两个表示真和假的神奇值(不是 0 和 1 ...)。我已经创建了一个 C++ class 包装这个 C 结构,它工作得很好。我已经将 set()
和 get()
方法实现为:
void Class::set(size_t index , bool value) {
if (value)
c_ptr[index] = SPECIAL_TRUE_VALUE;
else
c_ptr[index] = SPECIAL_FALSE_VALUE;
}
这没问题;但理想情况下我想重载 operator[],但我不清楚 how/if 我能做到吗 - 由于 bool 和整数值之间的特殊转换?
struct pseudo_reference {
operator bool()const&&{
return c->get(index);
}
pseudo_reference operator=(bool b)&&{
c->set(index, b);
return {c,index};
}
// sometimes having named functions is useful:
bool get() const&& {
return std::move(*this);
}
void set(bool b)&& {
std::move(*this) = b;
}
pseudo_reference()=delete;
private:
Class* c;
size_t index;
pseudo_reference(pseudo_reference&&o)=default; // not exposed
pseudo_reference(Class* pc, size_t i):c(pc),index(i){}
friend class Class;
};
在Class
中:
pseudo_reference operator[](size_t i){
return {this, i};
}
bool operator[](size_t i)const{
return c_ptr[index] == SPECIAL_TRUE_VALUE;
}
我存储了一个指针和一个索引,所以我避免在我的 pseudo_reference
中重新实现 get
/set
的逻辑。这样的 pseudo_references
可能是短暂的,因此大小优化可能并不重要。
我阻止了所有非右值操作以阻止存储 pseudo_reference
。您可以相对无害地对非右值操作进行限制,但根据我的经验,pseudo_references
值的行为类似于引用,因此最好不要持久化它们。
有人仍然可以通过 auto&& x = c[33];
存储 pseudo_reference
,但如果不 move
将无法使用它。希望这能抓住 大多数 容易出错的用法。 auto x = c[33];
不行。
您可以 return 包装器助手 class 为您处理分配。
struct WrapMe {
c_ptr_T &value;
WrapMe(c_ptr_T &_value) : value(_value) {}
// handles assignment of bool values
WrapMe & operator=(const bool b) {
value = (b) ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE;
return *this;
}
// handles cast to bool
operator bool() const { return value == SPECIAL_TRUE_VALUE; }
};
class Class {
WrapMe operator[](const int idx) { return WrapMe(c_ptr[idx]); }
// ...
};
要实现 operator[]()
,您需要 return 一个代理对象,当它出现在 =
的左侧时执行实际分配:
struct proxy {
proxy& operator=( bool value ) {
c_.c_ptr[ index_ ] = value ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE;
return *this;
}
operator bool() const { // for when it's just used normally, not =
return c_ptr[ index ] == SPECIAL_TRUE_VALUE;
}
private:
Class &c_;
size_t const index_;
proxy( Class &c, size_t index ) : c_( c ), index_( index ) { }
friend class Class;
}
class Class {
public:
proxy operator[]( size_t index ) {
return proxy( *this, index );
}
bool operator[]( size_t index ) const { // read-only access is easy
return c_ptr[ index ] == SPECIAL_TRUE_VALUE;
}
// ...
};
或者类似的东西。