使用回调重载operator =() [英] Overloading operator=() with callback

查看:121
本文介绍了使用回调重载operator =()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模板 Property ,它包装数据并提供其他服务。该模板专用于基本数据(float,int_32,bool ...),并且存在基本类型的向量的另一指定。例如:

 模板< typename T> 
属性:public PropertyBase
{
public:
//基本类型指定。
void operator =(T const& data);
}

template< typename T>
属性< std :: vector< T> > :public PropertyBase
{
public:
//基本类型向量的指定。
T const& operator [](std :: size_t i)const;
}

在基本数据的指定我已经重载 = ,以便在更改数据后调用回调。对于向量的指定,我已经重载 operator [] 以获得对向量的第i个元素的索引访问。



现在我想得到一个类似的行为,我在 operator = 在基本类型,但我的专业化的向量。我被困住了。我想做的是:

 属性< std :: vector< float> > myProp; 
myProp [5] = 5.21f;

,并期望在分配发生后调用回调。



问题是 myProp [5] 返回一个float,并且没有为float属性定义回调机制。



当然,我可以写一个索引的setter函数,例如

  template< typename T& 
属性< std :: vector< T> > :public PropertyBase
{
public:
//基本类型向量的指定。
T const& operator [](std :: size_t i)const;

void set(int i,T const& newValue);
}

但是使用setter语法并不像我预期的那么干净。 / p>

我也可以在 operator [] 中调用回调,但是在调用之前调用回调,而不是之后调用。



任何人都有一个想法,以获得这种干净的语法,同时仍然能够调用我的回调后,分配后



感谢!



PS:请注意,我的属性模板比并且检查T是否是一个基类型(这不是在这里),但这与我的问题不相关。

解决方案

您需要从运算符[]()返回一个代理,其中[隐含地]转换为您的类型 T ,并且有一个赋值操作符拦截赋值。这是一个草图:

  template< typename T& 
class proxy {
Property< std :: vector< T>> * property;
std :: size_t index;
public:
proxy(property< std :: vector< T>> * property,std :: size_t index)
:property(property)
,index {
}
operator T const&()const {return property-> get(index); }
T const& operator =(T const& other){
return this-> property-> set(index);
}
};

然后,您的 operator []()返回这样的代理:

  template< typename T& 
proxy< T>属性< std :: vector< T>> :: operator [](std :: size_t index){
return proxy< T&
}

字段的读取和写入的实际拦截将发生在相应的 set() get()成员。如果代理< T> ,则 >类。使用这样的代理类的主要问题是它不允许使用成员函数,例如:

 属性< ; std :: vector< std :: string>> p; 
p [0] .c_str();

由于 p [0] a 代理< T> 它没有 .c_str()函数。因为你声明你只支持某些基本类型,你可以支持代理上的合适的操作。使用代理类型的另一个问题是,它取出一个转换,严格地说,返回代理而不是引用的迭代器不是一个合适的迭代器(虽然我似乎记得迭代器要求在C + +11)。


I have a template Property which wraps a data and provides other services. This template is specialized for basic data (float, int_32, bool...) and there exists another specilization for vectors of basic types. Something like:

template<typename T>
Property : public PropertyBase
{
public:
    // Base types specilization.
    void operator=(T const & data);
}

template<typename T>
Property<std::vector<T> > : public PropertyBase
{
public:
    // Specilization for vectors of base types.
    T const & operator[](std::size_t i) const;
}

On the specilization for basic data I have overloaded operator= so that a callback is called after the data was changed. On the specilization for vectors I have overloaded operator[] to get indexed access to the ith element of the vector.

Now I would like to get a similar behavior that I have for operator= on basic types but with my specialization for vectors. I am stuck though. What I would like to do is something like:

Property<std::vector<float> > myProp;
myProp[5] = 5.21f;

and expect the callback to be called after the assignement happened.

The problem is that myProp[5] returns a float, and the callback mechanism is not defined for floats but Property.

Of course I can write an indexed setter function such as

template<typename T>
Property<std::vector<T> > : public PropertyBase
{
public:
    // Specilization for vectors of base types.
    T const & operator[](std::size_t i) const;

    void set(int i, T const & newValue);
}

But with the setter the syntax is not as clean as I would expect.

I can also call the callback in operator[] but then the callback is called before the assigment, not after.

Anyone has an idea to get this clean syntax while still being able to call my callback after the assigment?

Thanks!

PS: note that my Property templates are more complex than what is written and do check whether T is a base type or not (which is not done here) but this is not relevant for my question.

解决方案

You'll need to return a proxy from your operator[]() which [implicitly] converts to your type T and has an assignment operator intercepting the assignment. Here is a sketch:

template <typename T>
class proxy {
    Property<std::vector<T>>* property;
    std::size_t               index;
public:
    proxy(Property<std::vector<T>>* property, std::size_t index)
        : property(property)
        , index(index) {
    }
    operator T const&() const { return property->get(index); }
    T const& operator= (T const& other) {
        return this->property->set(index);
    }
};

Your operator[]() would then return such a proxy:

 template <typename T>
 proxy<T> Property<std::vector<T>>::operator[](std::size_t index) {
     return proxy<T>(this, index);
 }

The actual interception of the reading and writing of the fields would happen in the corresponding set() and get() members. These can be private if proxy<T> is made friend of the class. The main issue with using a proxy class like this is that it doesn't allow the use of member functions, e.g.:

Property<std::vector<std::string>> p;
p[0].c_str();

Since p[0] happens to be a proxy<T> it doesn't have a .c_str() function. Since you stated that you are only supporting certain basic types you could support the suitable operations on the proxy. The other issue with using a proxy type is that it takes out one of the conversions and, strictly speaking, an iterator returning proxies rather than references isn't a proper iterator (although I seem to recall that the iterator requirements were relaxed in C++11).

这篇关于使用回调重载operator =()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆