C++ C++;使用转换重载[]
我有一个表示布尔值向量的C数据结构;出于我无法控制的原因,布尔值在内部存储为整数,有两个神奇的值(不是0和1…)表示真和假。我创建了一个C++类来封装这个C结构,它工作得很好。我已经实现了C++ C++;使用转换重载[],c++,overloading,C++,Overloading,我有一个表示布尔值向量的C数据结构;出于我无法控制的原因,布尔值在内部存储为整数,有两个神奇的值(不是0和1…)表示真和假。我创建了一个C++类来封装这个C结构,它工作得很好。我已经实现了set()和get()方法,如下所示: void Class::set(size_t index , bool value) { if (value) c_ptr[index] = SPECIAL_TRUE_VALUE; else c_ptr[index] =
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;
}
这工作正常;但理想情况下,我希望重载运算符[],但是我不清楚如何/是否可以做到这一点-由于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;
};
在类中
:
pseudo_reference operator[](size_t i){
return {this, i};
}
bool operator[](size_t i)const{
return c_ptr[index] == SPECIAL_TRUE_VALUE;
}
我存储了一个指针和一个索引,因此避免了在我的伪参考
中重新实现get
/set
的逻辑。这种伪_引用可能是短期的,因此大小优化可能并不重要
我阻止了所有非右值操作,以阻止存储伪\u引用
。您可以相对无害地使所述操作不受右值限制,但根据我的经验,pseudo_references
是行为类似于引用的值,因此如果它们不持久就更好了
有人仍然可以通过auto&&x=c[33]存储pseudo_引用代码>,但如果不移动它,就无法使用它。希望它能抓住最容易出错的用法<代码>自动x=c[33]代码>无效。您可以返回一个包装器帮助器类,该类为您处理分配
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]); }
// ...
};
要实现操作符[]()
,您需要返回一个代理对象,当它出现在=
的左侧时,该代理对象执行实际赋值:
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;
}
// ...
};
或者类似的东西。您需要阅读一些关于代理类的内容是的——我今天已经了解了代理类——以及重载赋值运算符;这对于你的解决方案来说可能是可行的,也可能是不可行的,但是你应该考虑转换的频率和布尔访问的频率。如果您主要使用set/get/[]函数,而很少使用特殊的_*_值转换,则只存储布尔值,然后仅在需要时进行转换可能会更容易。为了响应@user1978011的编辑尝试,我特意将其设置为私有。friend类
应该允许class
构造pseudo\u引用
s。好吧-我想我了解它是如何工作的?您将为对set()
方法的每次访问实例化一个伪\u引用?这看起来确实有点重?@user422005它是一个指针(指向类
)和一个大小
。那重物怎么这么重?引用通常是作为指针实现的(如果不是内联的,则不存在),因此我们只讨论返回数据引用的几个字节。一个称职的编译器可以将其内联到不存在的状态,因为它的寿命只够在指针上调用set
或get
。对get
或set
的原始调用进行优化分析,如果有很大差异,我会感到震惊。立即消失的小堆栈对象很便宜。@Yakk,你能用bool操作符[](size\t i)const
来代替operator bool()const
?这样,只要处理右值访问,就可以将代理转换为bool
。我记得在通过代理读取时看到过这种转换,但我想再次检查。@vsoftco aconst\u proxy
与proxy
通常是不同的类型(它不仅仅是const proxy
——有点像指针,const指针
不同于指向const
的指针)。我让[]const
直接返回值,而不是编写一个只调用get
deferred的奇特类。看起来更简单,不是吗?