对C++的改造#2 属性(2)

这次这篇就讲一下怎么把之前定义的属性变平滑,我之前就说了,把能重载的运算符都重载一遍就行了

单目运算符:

#define OPERATOR1(op) \
template<class T>    auto operator op (const Property<T>& l) -> decltype(op l->get()){        return op l.get();    }

OPERATOR1(!);
OPERATOR1(~);
OPERATOR1(*);
//不建议重载取地址运算符,如果你确实需要的话也可以重载
//OPERATOR1(&);

#undef OPERATOR1

双目运算符:

#define OPERATOR2(op) \
template<class L, class R> auto operator op (const Property<L>& l, const R& r) -> decltype(l.get() op r) {     return l.get() op r; } template<class L, class R> auto operator op (const Property<L>& l, const Property<R>& r) -> decltype(l.get() op r.get()) {     return l.get() op r.get(); } 

    OPERATOR2(+);
    OPERATOR2(-);
    OPERATOR2(*);
    OPERATOR2(/);
    OPERATOR2(%);
    OPERATOR2(>>);
    OPERATOR2(<<);
    OPERATOR2(|);
    OPERATOR2(||);
    OPERATOR2(&);
    OPERATOR2(&&);
    OPERATOR2(^);
    OPERATOR2(>);
    OPERATOR2(<);
    OPERATOR2(>=);
    OPERATOR2(<=);
    OPERATOR2(==);
    OPERATOR2(!=);

#undef OPERATOR2

复合运算符:

#define OPERATOREX(op) \
template<class L,class R> Property<L>& operator op##=(Property<L>&l, const R& r) {     auto v=l.get();    v op##= r;    l.set(v);     return l; } template<class L,class R> Property<L>& operator op##=(Property<L>&l, const Property<R>& r) {     auto v=l.get();    v op##= r.get();    l.set(v);     return l; } 

    OPERATOREX(+);
    OPERATOREX(-);
    OPERATOREX(*);
    OPERATOREX(/);
    OPERATOREX(%);
    OPERATOREX(>>);
    OPERATOREX(<<);
    OPERATOREX(|);
    OPERATOREX(&);
    OPERATOREX(^);

#undef OPERATOREX

自增自减运算符:

  template<class T>
    auto operator++(Property<T>& l, int) -> decltype(l.get()++) {
        auto x = l.get();
        auto ret = x++;
        l.set(x);
        return ret;
    }

    template<class T>
    auto operator++(Property<T>& l) -> decltype(++l.get()) {
        auto x = l.get();
        ++x;
        l.set(x);
        return x;
    }

    template<class T>
    auto operator--(Property<T>& l, int) -> decltype(l.get()--)         {
        auto x = l.get();
        auto ret = x--;
        l.set(ret);
        return ret;
    }

    template<class T>
    auto operator--(Property<T>& l) -> decltype(--l.get()) {
        auto x = l.get();
        --x;
        l.set(x);
        return x;
    }

重载中括号(写在类里面)

//作左值
template <class I>
auto operator[](I i) -> decltype(_value[i])&{
    return _value[i];
}
//作右值
template <class I>
auto operator[](I i) const -> const decltype(_value[i])& {
    return _value[i];
}

重载箭头(写在类里面)

const T operator->() const{
    return get();
}

T operator->() {
    return get();
}

重载圆括号(写在类里面)

template<class... Types>
auto operator()(Types...args) -> decltype(_value(args...)){
    return _value(args...);
}

template<class... Types>
auto operator()(Types...args) const -> decltype(_value(args...)) {
    return _value(args...);
}

好了,现在能重载的运算符就都重载了,剩下还有一些不能重载的运算符,那些也无能为力了,不过除了点号"."其余要么不常用,要么没重载的必要,而点号禁止重载我们也没办法,但是我们可以重载箭头运算符,我们可以在被包装类型不是指针型的时候用箭头进行被包装类型的成员调用,点号进行属性类型的成员调用。而被包装类型时指针时保持原含义。

那么上面的重载箭头需要改改了,运用模板类型的特化:

template<class T>
class Property{
...
    const T* operator->() const{
        return &get();
    }

    T* operator->() {
        return &get();
    }
...
}

template<class _T>
class Property<_T*>{
...
    typedef _T* T;
...
    const T operator->() const{
        return get();
    }

    T operator->() {
        return get();
    }
...
}

不过这种写法有个缺点,就是如果被包装的类型重载了箭头运算符,那么将无法调用,虽然这种情况较少,但到底怎么重载箭头运算符还是看个人喜好吧。

关于属性的东西就暂时这样了,当然,还没完,还记得C#有个依赖项属性么,还有属性绑定之类的东西,不过那个东西需要处理事件,所以下一章不出意外的话就是类似Event或者Delegate之类的东西的实现。

对C++的改造#2 属性(2)

时间: 2024-11-23 22:52:50

对C++的改造#2 属性(2)的相关文章

web前端入门到实战:CSS Display属性的双值写法

display属性 display 属性用来控制一个元素及其子元素的 格式化上下文, 你应该在刚刚学习CSS的时候就知道,有些元素是块级元素,有些则是行内元素. 有了 display 属性,你就可以切换元素不同的状态.比如说,通常一个 h1 元素是一个块级元素,但是通过切换,它就能以内联元素展现. 这几年,我们也知道了Grid 布局和弹性盒布局.我们只需要将 display 属性的值设置为 display: grid 或 display: flex 就可以实现这两种布局.当 display 属性

python核心编程--笔记

python核心编程--笔记 的解释器options: 1.1 –d   提供调试输出 1.2 –O   生成优化的字节码(生成.pyo文件) 1.3 –S   不导入site模块以在启动时查找python路径 1.4 –v   冗余输出(导入语句详细追踪) 1.5 –m mod 将一个模块以脚本形式运行 1.6 –Q opt 除法选项(参阅文档) 1.7 –c cmd 运行以命令行字符串心事提交的python脚本 1.8 file   以给定的文件运行python脚本 2 _在解释器中表示最后

django 自定义分页模块

django 自定义分页模块 from django.shortcuts import render, HttpResponse, redirect from django.utils.safestring import mark_safe class Page(object): def __init__(self, current_page): self.current_page = int(current_page) @property def start(self): return (se

Fit项目分页组件的编写

项目中涉及列表显示的地方都会用到分页控件,为了能更好地与当前网站的样式匹配,这次要自己实现一个. 所以选择了模板中提供的分页样式,基于模板改造以能够动态生成: 一 控件的行为规则 a) 可设置显示几个页码(默认5个,只能是奇数) 如果当前页显示5个,则默认前后各有两个,比如当前页是5,显示页码为"3 4 5 6 7 如果当前页在最前面,比如为1,显示页码为:1 2 3 4 5 同样当前页在最后面,比如为9,显示页码为:5 6 7 8 9 如果总页数少于5,比如只有3页,则页码全部显示:1 2 3

蜗牛历险记(二) Web框架(上)

接上篇所说,本篇主要内容是讲述如何使用Autofac来管理整个平台的生命周期(初级). 一.简述 插件式Web开发的同学应该还会记得PreApplicationStartMethod这个Assembly级别的Attribute,它可以在应用程序启动之初(Web启动之前)启动,一般我们用它来做一些插件资源拷贝.插件动态加载的工作. [assembly: PreApplicationStartMethod(typeof(PreApplicationInit), "InitializePlugins&

百度地图信息提示框的修改 转

http://blog.csdn.net/jankercsdn/article/details/45392635 版权声明:本文为博主原创文章,未经博主允许不得转载. 一个小项目,百度地图的定制,电脑用的是触摸屏,支持手写输入,中文输入直接调用系统的虚拟键盘,手写输入是参考网上高手写的一个控件. 百度的信息提示框里的搜索框里要输入查询地址,就是去哪里,到哪里那个地址输入框,要解决的问题是怎么把虚拟输入键盘的内容赋值到这个地址输入框,并要判断当前是哪个输入框. 一般运用信息提示框是调用这个库“ht

Python之路【第十九篇】自定义分页实现(模块化)

自定义分页 1.目的&环境准备 目的把分页写成一个模块的方式然后在需要分页的地方直接调用模块就行了. 环境准备Django中生成一个APP并且注册,配置URL&Views 配置URL from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^user_lis

swift:UIKit中Demo(二)

这一节,继续为大家提供一个Demo,用来说明Swift中的各种语法及在UIView中的基本使用.效果图如下: 看起来,这个Demo非常的简单.但是为了进行详细的语法说明,它的实现,均是用代码实现的,并且下方的进度条都是"组装"起来的. 结构分析: 1. 有一个根控制器ViewController.swift, 它只是用来展示上面显示的文字(秋恨雪). 2. 然后下面的文字大小切换及进度条这个整体是一个自定义的View(LFFontView.swift) 3. 进度条部分又有三部分内容组

C# 控制反转

2006年多部贺岁大片以让人应接不暇的频率纷至沓来,其中张之亮的<墨攻>算是比较出彩的一部,讲述了战国时期墨家人革离帮助梁 国反抗赵国侵略的个人英雄主义故事,恢宏壮阔,浑雄凝重的历史场面相当震撼.其中有一个场景:当刘德华所饰的墨者革离到达梁国都城 下,城上梁国守军问:"来者何人?",刘德华回答:"墨者革离!",我们不妨用C#(原文是java,我修改)对这段"城门问对"的场景进行编剧并借由这个例子来理解IoC的内涵. 剧本和饰演者耦合