我害怕全真账本

  • 作为一个资深的财务人员

  • 我害怕全真账本

  • 我害怕全真账本,一用它,我就象一个战国时代的神箭手参加现代射击,扣动扳机,才发现还不如一个新兵。

  • 我引以为傲的专业是什么?不就是对老式记账软件的繁琐流程如数家珍,如先要进行账套初始化,才能设置科目,然后才是初始余额设置。凭证添加后要审核,审核之后要过账……。但全真账本却没有流程,你只需要做好凭证,账就做好了。我对老式记账软件的修改也了如指掌:首先逐月进行反结账到要修改的月份,才能修改对应的凭证,然后按序过账,直至完成。但全真账本中把数据锁打开,改了就行。相较之下,我的专业显得更象是古代少女脚上的裹脚布,又臭又长,不但多余,还妨碍身体。

  • 我害怕全真账本,它有本地云上双备份,万一老板得罪了我,砸了硬盘,删除库跑路,都不可能,因为要删除云上的数据备份,除非我的死党在阿里云,恰好还管着同一款产品,并愿意为我在牢里度过一生。更可恨的是,即使我想要一个筹码从云上恢复一个备份,竟然还需要得到老板的短信验证。

  • 我害怕全真账本,它的凭证、账本精美得就象广告宣传单页,在它面前,我打印出的账本,就象是小学生美术课上的临摹作品。更何况它竟还有票据打印。

  • 我害怕全真账本,它让我知道,把简单的事搞得很复杂是多么的愚蠢,而更可怕的是,我的专业全建立在这种愚蠢之上。

  • 我希望没人知道全真账本,因为这样就没人知道我的不安,免得被他们发现我的落寞,甚至连安慰我的心思都没有。

  • 我害怕全真账本,它让新入职的财务小白,一个小时得到的专业素养,就超过了我的一生。

  • 我害怕全真账本,我更害怕知道它的老板,使用它的人。

当我站在优秀员工竞选演讲台上时,台下传来一阵嘘声,但


当我站在优秀员工竞选演讲台上时,

台下传来一阵嘘声

但——

这不能怨他们。

因为,

我只是一名普通的出纳。

“一个出纳也敢上优秀员工竞选? ”

“是的。”有人附和道。

如果你知道一年前的这个时候我有多狼狈,你肯定也会在内心冒出一句:

“她怎么敢?”

的确,一年前,要让我上这个演讲台,我也会问自己:

“你怎么敢?”

和很多当代的年青人一样,我和老公也是背井离乡,在外打拼。为了生小孩,我辞职在家呆了两年多。去年,好不容易在这家公司找了一份出纳的工作,狠心把女儿送到了托儿所。

你有小孩吗?

你知道一个两岁多点的小女孩突然离开妈妈去到一个陌生的环境跟一堆陌生的人在一起的样子吗?

每天早上送她去上学,都象是死刑犯要上刑场。

你可以想想一个妈妈每天送一次自己的孩子上刑场的样子吗?

肝肠寸断——却又无可奈何!

每当手机铃声响起,我都会有一种莫名的恐惧,——千万别是老师的电话。

“全园就你女儿一个人不做操,不跳舞!”

这句话我印象深刻。

几百人的操场上; 整齐的广播体操队列中; 萌宠可爱的歌舞群里;总有一个丫头默默地站在那儿啃手指头……

每当看到这个场景,我就不由自主地想起老祖宗的一句话“父母在,不远游。”

多么深刻呀,这可能也是我们这一代人注定背负的原罪吧!

但,有什么办法呢?

你知道一个远离职场两年多还有一个两岁多小孩的女人找工作有多难吗?

有个人力资源总监私下跟我说,你的条件很好,可我不敢录你呀,我怕哪天你突然说要生二胎。

我很珍惜这份工作。工作中小心翼翼,生怕出一点错误,谁知道年底一对账,还是发现几个月前出现几笔数字记错顺序,造成明细异常。人在高压与焦虑中想不出错真的很难。

我为此熬了几个通宵,拆了已装订的凭证,重新誊写了全部的账本。但好事不出门,坏事传千里,这件事仍然在公司人尽皆知。

你说,我敢参加年度优秀员工竞选演讲吗?

一个不甘平凡的普通人,在一个普通的岗位,用尽心力想把工作做好,却连普普通通,都没做到。

我心情很低落。

“亲爱的,今天送你的礼物,你一定喜欢。”

元旦,老公神秘兮兮地对我说:

“这是我花了三个月的时间,找遍了全网,试了能找到的所有记账软件,帮您选的。”

我将信将疑,作为一个重点大学毕业生,我当然想过试过很多的记账软件,但一个个庞大臃肿,界面丑陋,使用麻烦,规矩繁多,为了记个账,仿佛自己成了大户人家的丫鬟,真还不如我用电子

表格记好了再抄录到账本上省心便捷,关键是那一切尽在掌握的自主感,很安心。

在我的疑惑中,他自信地打开笔记本电脑,我一眼就发现桌面上多了一个蓝色账本图标,名字叫做“全真云账本”。

《全真云账本》,我以前怎么没见过?

“这是新近出的一款记账软件,你只需要输入凭证,系统就会根据凭证生成你需要的各种账表,试试?”

在老公得意的眼神的注视下,我打开了它。

哇,这凭证、账本、一点也没有市场上多如牛毛的记账软件各自吹捧的仿真界面的山寨味,比我们公司买的真实的印刷账本还要漂亮!

一次、二次……,从登录到完成第一张现金付款凭证仅用了六次鼠标单击。是的,键盘都没用到,而账本竟然已经生成好了……

许多公司花大价钱从很牛的软件公司买回来,还要让员工花几个月的时间学习的记账软件,竟然被它简化成了一件事——做凭证。

可仔细一想,难道记账软件不是本该这样吗!

没有流程、没有套路,满满的掌控感。

看得出,老公为了找这款软件,真费了不少心。

演讲台下仍在交头接耳,声音麻雀一样地起伏。

每次看着打印出来的美得象是广告宣传单的凭证与账本,就象在欣赏女儿试卷上的一百分。

我觉得自己的工作也得了一百分。

但——

这并不能给我走上这个演讲台的勇气。

乱世出英雄,难时显本事。

不久前公司经历了一次火灾。

写字楼楼下失火,火灭后,财务室里一片狼藉,高温后的电脑都变了形,不时还能听到消防车喷射后残留的水珠滴落的声音……

领导心急如焚,马上让我们评估损失情况,由于消防抢救及时,加上保险柜很厚重,别的没有什么损失, 但几套桌椅与电脑是用不成了。

那账务数据怎么办呀?

我底气十足:

“请领导放心”!

因为《全真云账本》,它有云备份呀!

演讲台下的议论声更大了。

我按下幻灯片的播放按钮,屏幕上出现了火灾后的财务室。

台下瞬间一片肃静。

大家仿佛又回到了火灾现场,各自回顾着被损毁的东西:书、文件,以及到今天还在补救的项目计划书……,心情就象灾后墙角滴落的水滴。

下一页,屏幕上变成了我的凭证、账本,整个会场好象都松了一口气。

滴落着水滴的办公室与精美得像广告宣传单页的凭证与账本。

混乱与秩序,丑陋与美丽,强烈的对比,带来胜利般的愉悦,台下传出了强烈的赞叹。

更重要的,我的出纳工作没有耽误公司一个人的报销,一笔业务的转账。

……

还没来得及鞠躬,演讲就被掌声打断。

“我要感谢很多人,但最应该感谢的是我的老公,还有《全真云账本》。”

没有人听见我的感谢,因为,掌声已象钱塘江的潮水淹没了观潮的人。

从演讲台上下来,我知道,我赢了。

在心里,我默默地说:

“谢谢你,老公”。

“谢谢你,《全真云账本》”!

《全真云账本》的网址:

https://MYQZZ.COM

希望也能帮到你。

EffectiveModernC++

目录

  • 1 Deducing Types
  • 2 auto
  • 3 Moving to Modern C++
  • 4 Smart Pointers
  • 5 Rvalue References, Move Semantics, and Perfect Forwarding
  • 6 Lambda Expressions
  • 7 The Concurrency API
  • 8 Tweaks

1. Deducing Types

1. 理解模板类型参数推导
    1. reference-ness忽略
     2. universal reference:T&&
     3. 数组类型:T (&)[N]
     4. 推导by-value参数时,const和volatile被忽略
2. 理解auto类型推导
    1. auto x3 = { 27 }; //x3类型是std::initializer_list<int>(对auto,要求元素须是相同类型),不是int
    2. initializer常量不能用于void f(T param);的模板参数类型推导,但声明为void f(std::initializer_list<T>)可以
    3. C++14允许函数返回值类型的推导,用的是template type deduction,不是auto type deduction

3. 理解decltype
    1. bool f(const Widget& w); // decltype(w) is const Widget&, decltype(f) is bool(const Widget&)
        1. 注意,函数类型的写法(ReturnType(ArgsType))之前似乎没见过,好像是后来流行的?
    2. 主要用途:声明依赖于函数参数的返回值类型
        1. auto f(Container& c, Index i) -> decltype(c[i]) { ... }
            1. 完善为 -> decltype(std::forward<Container>(c)[i])
        2. 但operator[]可能对std::vector<bool>特化模板容易出问题
    3. C++14 decltype(auto):可以正确处理引用类型的推导(因为decltype对左值类型总是返回T&)
            1. decltype(auto) f(Container&& c, Index i) { ...return std::forward<Container>(c)[i]; }
    4. 对int x=0; decltype(x)得到int,decltype((x))返回int&

4. 怎样在IDE里查看编译器推导的类型

2. auto

1. 优先使用auto
    1. std::function比auto慢?(总感觉这是编译器优化的问题)
    2. v.size()是std::vector<int>::size_type类型(unsigned),使用auto可避免这个记忆负担?
    3. for (const auto& p : m) { ... } //为什么不是for(auto p : m)?
2.所谓的可不见的内部代理类:auto highPriority = static_cast<bool>(features(w)[5]);

3. Moving to Modern C++

1. 区别()与{}(初始化对象)
    1. 如果类定义了std::initializer_list构造函数的话,{}优先匹配(不管实际的参数类型)//C++编译器的灵活性有点缺乏
        1. 用空std::initializer_list初始化:Widget w4({}); //直接Widget w4{};调用默认构造
    2. 变参模板(这让我想起了Scheme syntax-rules变态的模式匹配语法)
        1. template<typename T, typename... Ts>
        2. void doSomeWork(Ts&&... params){
            1. T localObject(std::forward<Ts>(params)...);
2. Prefer nullptr to 0 and NULL(这样的条款有点侨情)
    1. f(nullptr); // calls f(void*) overload
3. Prefer alias declarations to typedef's
    1. 别名声明:using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;
        using FP = void (*)(int, const std::string&);
        template<typename T> using MyAllocList = std::list<T, MyAlloc<T>>;
            老实的写法:需要typename告诉编译器内部名字是一个类型不是变量,没有using好?
    基于<type_traits>的类型特性擦除:
        std::remove_const<T>::type
        std::remove_reference<T>::type
4. Prefer scoped enums to unscoped enums
    enum class Color { black, white, red }; //但这样一来,引用枚举量时都需要那个枚举类名前缀
    enum class Status: std::uint32_t;
5. =delete
6. overriding发生的前提:***
    基类需要声明virtual
    函数名必须相同(废话)
    参数类型必须相同(*)
    const性质必须相同(*)
    返回类型和异常规格必须兼容(*)
    C++11:引用限定必须相同:void f() &; void f() &&;(代表f只能在左值/右值对象上调用)
7. override是上下文关键字(C++11特性),可用作函数名称
8. Prefer const_iterators to iterators
    作者又在强调常量迭代器了,但实际上,STL的非常量迭代器通常更有效
    定义非成员版本的cbegin://优先非成员只不过是作者偏好FP风格的体现
        template <class C> auto cbegin(const C& container)->decltype(std::begin(container)) { ... }
            注意,const类型修饰只是为了让编译器帮助我们完成一些编译器的类型安全检查
9. noexcept
    vs C++98 throw() //差别在发生异常时的stack unwinding处理上,略
    有条件的noexcept:noexcept(noexcept(swap(*a, *b)))
10. constexpr
    代表const in const out,可用作编译期的常量
    C++11里对函数的一些限制:略(这只不过是编译器的实现问题,C++有时候老是会把语言、库与编译器实现混淆在一起!)
    *C++14:setter也可以是constexpr
11. const成员函数应该是线程安全的
    可以修改mutable数据成员
    如果要一次修改多个atomic,使用mutex保护一致性:std::lock_guard<std::mutex> g(m);
12. 理解特殊的成员函数生成
    copy操作(构造&赋值)、move操作
    C++11里,如果用户定义了dtor(析构函数),则move操作不会自动生成 => 可使用=default绕过
    Member function templates never suppress generation of special member functions(C++里的偏僻规则太多了)
        有些规则只对库设计者才有意义,使用者(App开发者)只需遵循编码规范就可以了

4. Smart Pointers

1. C++11: std::auto_ptr, std::unique_ptr, std::shared_ptr, and std::weak_ptr
2. std::unique_ptr
    1.定制deleter:
        auto delA = [](A* a){ ... delete a;}
        std::unique_ptr<A, decltype(delA)> makeA(...){ ... }
    转换为std::shared_ptr
3. std::shared_ptr
    1. 通常,保存引用计数的'控制块是动态分配的
        但std::make_shared将控制块与对象内存绑定到一起,这给对象的真正释放内存带来了麻烦
        对比:std::shared_ptr<Widget> spw1(pw, loggingDel); //创建一个新的控制块
    2. 奇特递归模板:class Widget: public std::enable_shared_from_this<Widget> { ... }
        shared_from_this()之前需要已有std::shared_ptr引用
            ==> private ctor,+定义static create方法
4. std::weak_ptr
    1. 弱引用指针通常与引用计数指针配合使用:std::weak_ptr<Widget> wpw(spw);
        1. if (wpw.expired()) ...
        2. auto spw2 = wpw.lock();
    2. 实现细节:std::shared_ptr的控制块中存储了弱引用计数?
5. std::make_unique和std::make_shared
    1. 资源泄漏:processWidget(std::shared_ptr<Widget>(new Widget), computePriority());
        1.==> processWidget(std::make_shared<Widget>(), computePriority());
6. 当使用Pimpl习俗时,需要定义特殊的成员函数(dtor及move操作)
    定制deleter是std::unique_ptr类型的一部分,但不是std::shared_ptr类型的一部分

5. Rvalue References, Move Semantics, and Perfect Forwarding

1. 即使声明为void f(T&& a); 参数总是左值
2. 理解std::move和std::forward
    1. std::move和std::forward既不移动也不转发,只是类型转换(运行时什么也不做)
    2. std::move无条件把参数转换为右值,而std::forward要求实参必须是右值(注意,形参总是左值)
        1. move构造函数的参数是非const的,但copy构造函数的参数是const的,这一差别允许const右值实参调用copy构造
    1. std::move总是可以换成std::forward
3. 区别‘通用引用’和右值引用
    1. 不是右值引用:
        1. void f(T&& param);
        2. auto&& var2 = var1; //前提:存在类型推导
    2. 右值引用:
        1. void f(Widget&& param);
        2. Widget&& var1 = Widget();
        3. void f(std::vector<T>&& param);
        4. void f(const T&& param);
        5. 即使写成T&&但不存在类型推导的情况(从类模板实例化得到的成员函数 vs 成员函数模板)
    3. C++14:
        1. [](auto&& func, auto&&... params){ std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...); }
4. 在右值引用上使用std::move,在通用引用上使用std::forward
    1. return std::move(lhs); //不发生“copy到临时对象”,注意lhs是‘通用引用’(T&&类型参数)
    2. 不要return std::move局部对象(这种情况下反而无法RVO)
        1. 编译器能够做RVO,即使你不写成return Widget();?
            1. 这里面有点扯淡,因为仅仅是“C++标准委员会”这么说的,作者似乎混淆了TMP(模板元编程)和普通的写法
5. Avoid overloading on universal references
    1. copy构造函数的参数总是const的,一个非const的参数将优先匹配universal reference构造函数模板
6. tag dispatch?脑抽!
7. std::enable_if
    1. typename = typename std::enable_if<condition>::type //靠,真是疯狂
    2. typename std::decay<T>::type:去除类型T的引用、const、volatile修饰
        1. condition:!std::is_same<Person, typename std::decay<T>::type>::value
        2. C++14语法:std::decay_t<T>(不必再写typename)
8. std::is_base_of<T1, T2>::value
9. 理解引用塌陷
        1. 不允许用户声明引用的引用,但是编译器可以这么做?只要有一个是lvalue引用,结果就是左值引用
        2. 4个上下文:模板实例化、auto类型推导、typedef和using类型别名、decltype
10. 完美转发
    1. template<typename T> void fwd(T&& param){ f(std::forward<T>(param)); }
    2. template<typename... Ts> void fwd(T&&... param){ f(std::forward<T>(param)...); }
    3. 失败的情况:(无法类型推导,或不正确的推导)
        1. braced initializer:void f(const std::vector<int>& v); ==> fwd({ 1, 2, 3 });
        2. 0 or NULL as null pointers
        3. 重载的函数指针、模板函数 ==> 手工地指定函数重载或实例化版本
        4. struct中的bit域(无法以非const寻址)
    4. p211 references are simply pointers that are automatically dereferenced

6. Lambda Expressions

1. 避免默认捕获
    1. using FilterContainer = std::vector<std::function<bool(int)>>;
    2. filters.emplace_back( [](int value) { return value % 5 == 0; } );
    3. [&] 与 [=]
    4. 不能捕获成员变量,捕获的是this指针(隐式)
        1. 全局变量和static局部变量是引用不是捕获,捕获真针对局部变量(?)
2. Use C++14 init capture to move objects into closures
    1. auto pw = std::make_unique<Widget>();
    2. auto func = [pw = std::move(pw)] { ... }
        1. => auto func = [pw = std::make_unique<Widget>()] { ... }
    3. move capture的C++11仿真:
        1. auto func = std::bind( [](const std::vector<double>& data){...}, std::move(data) );
        2. Chromium代码里有类似的写法:void InProcessCommandBuffer::Destroy() {
            1. base::WaitableEvent completion(true, false);
            2. bool result = false;
            3. base::Callback<bool(void)> destroy_task = base::Bind( &InProcessCommandBuffer::DestroyOnGpuThread, base::Unretained(this));
            4. QueueTask(base::Bind(&RunTaskWithResult<bool>, destroy_task, &result, &completion));
        3. mutable lambda?(见鬼,之前怎么没见过这种语法)
3. Use decltype on auto&& parameters to std::forward them
    1. C++14 泛型lambda?:auto f = [](auto x){ return func(normalize(x)); };
    2. 完美转发:
        1. auto f = [](auto&& param){ return func(normalize(std::forward<decltype(param)>(param))); };
        2. variadic的版本:略
4. Prefer lambdas to std::bind
    1. bind对象(实际上是一个函数对象,注意,lambda也是!)
    2. lambda更可读(这倒是真的,bind有点像FP里的currying)
    3. p233 C++14 using namespace std::literals; //特殊的类型常量后缀语法,如1h 30s
    4. bind传参now()的话,传的是bind时的时间,而不是目标函数被调用时的时间(嗯,这让我想起了JavaScript里类似的问题)
        1. 推迟求值:auto setSoundB = std::bind(setAlarm,
            1. std::bind(std::plus<>(), steady_clock::now(), 1h), _1, 30s);
    5. 注意这里的语法,bind嵌套了bind以惰性求值
    6. std::bind总是复制参数,但可以用std::ref来传引用:
        1. auto compressRateB = std::bind(compress, std::ref(w), _1);
    7. std::bind可接受任意类型,假设PolyWidget::operator()是成员模板,则可:auto boundPW = std::bind(pw, _1);
        1. C++11 lambda:无等价形式
        2. C++14:auto boundPW = [pw](const auto& param){ pw(param); }; //但这种多态lambda有实际用途吗

7. The Concurrency API

1. Prefer task-based programming to thread-based
    1. auto futureResult = std::async(doAsyncWork);
    2. 线程:硬件(CPU)、软件(OS)、std::thread对象
        1. 即使函数不抛异常:int doAsyncWork() noexcept;,std::thread t(doAsyncWork);也有可能因为资源不足抛错
        2. oversubscription问题(增加了调度开销)
    3. std::async有可能在当前线程里执行doAsyncWork(异步的形式,实质却是同步函数调用),避免了线程过载
    4. GUI线程响应问题:显示指定std::launch::async启动策略
        1. 话说这里的讨论似乎与Chromium impl-side painting的目标有相通之处。。。
2. Specify std::launch::async if asynchronicity is essential
    1. 启动策略:std::launch::async 或 std::launch::deferred(直到在future上get/wait,此时同步执行)
    2. if (fut.wait_for(0s) == std::future_status::deferred){ //那么直接同步调用?
    3. 作者怎么这么喜欢写wrapper函数?std::result_of<F(Ts...)> ...
3. Make std::threads unjoinable on all paths
    1. implicit join:线程对象的析构函数会等待线程的执行完成(C++的这个API设计其实是有问题的,应该像Java那样提供显式的start方法)
    2. ~ThreadRAII():if (t.joinable()) { t.join() or detach() }
4. Be aware of varying thread handle destructor behavior
    1. 线程执行结果:不能存在callee的std::promise,也不能是caller的std::future(可转换为shared_future)
        1. ==> shared state(实际上存放在堆里)
    2. The normal behavior is that a future’s destructor destroys the future object. That’s it.
    3. ?
    4. std::packaged_task(略)
    5. The final future referring to a shared state for a non-deferred task launched via std::async blocks until the task completes
        1. 这话说得太拗口了,其实不就是在析构函数里阻塞等待嘛
5. Consider void futures for one-shot event communication
    1. std::condition_variable cv; //条件变量上wait有可能导致CPU繁忙吗?
    2. std::mutex m; //条件变量需要互斥访问,用mutex来保护
    3. 通知方:cv.notify_one();
    4. 等待方:{std::unique_lock<std::mutex> lk(m); cv.wait(lk); ...}
    5. 问题:
        1. mutex是否必需?
        2. wait之前notify将导致hang
        3. spurious wakeups:wait不是由于notify(这种情况下需要把wait放到while循环里?)
    6. 由于只通知一次,考虑使用一个开关状态变量:std::atomic<bool> flag(false);
        1. while (!flag); //但是这样会导致忙等
    7. 使用普通bool flag; 但是用mutex加锁:
        1. {std::lock_guard<std::mutex> g(m); flag = true;} cv.notify_one();
        2. {std::unique_lock<std::mutex> lk(m); cv.wait(lk, [] { return flag; }); ...} //避免了notify信号丢失的问题
    8. caller-callee一次通信:使用future-promise
        1. std::promise<void> p;
        2. 通知方:p.set_value();
        3. 等待方:p.get_future().wait(); //没有mutex?那就是说没有加锁,那么底层是怎么做到的?
        4. 注意,promise和future之间是一个动态堆分配的shared_state
    9. p269 如果发生了异常的情况?(C++这种命令式语言要在异常情况下仍然能够保证事务处理的一致性恐怕有点困难)
    10. auto sf = p.get_future().share(); ...(下略)
6. Use std::atomic for concurrency, volatile for special memory
    1. volatile:不能保证读与写操作的原子性,并且‘数据竞争’可导致无法预测/未定义的行为(编译器可生成任意指令?)
    2. std::atomic限制了指令重排:写操作完成之前,不允许后续指令提前执行(感觉这更像是Java里的volatile?)
    3. volatile std::atomic<int> vai;

8. Tweaks

1. Consider pass by value for copyable parameters that are cheap to move and always copied
    1. 重载 const std::string& 和 std::string&&
    2. T&& 加 std::forward<T>
    3. std::string传值 加 std::move
    4. C++98:经典的slicing问题(指的是一个子类对象传值给一个基类形参)
2. Item 42: Consider emplacement instead of insertion
    1. 42,不错的数字~
    2. 直接传递一个字符串常量给一个std::string&参数?临时对象析构和std::move开销
        1. vs.emplace_back("xyzzy"); //使用完美转发,直接在vector<string>容器内部构造一个string对象
    3. 嗯,把它称为‘就地插入’
    4. heuristics:
        1. The value being added is constructed into the container, not assigned
        2. The argument type(s) being passed differ from the type held by the container
        3. The container is unlikely to reject the new value as a duplicate
    5. 对shared_ptr不适用vp.emplace_back( new Widget())?
        1. 但是如果先构造td::shared_ptr<Widget> spw(new Widget, killWidget);的话,则push_back、emplace_back无差别
    6. 与explicit构造函数的交互
        1. 可以regexes.emplace_back(nullptr);,那是因为regex允许从nullptr explicit构造
            1. std::regex r(nullptr); 可以通过编译,但是属‘未定义行为’
            2. 注意,前者是直接初始化,而std::regex r=nullptr;写法是拷贝初始化 

如何从网上下载现成的模板

我们以农业银行现金缴款单为例来说明:

首先:在《打印专家》软件的票据视图中选中【现金缴款单】。

第一步:单击右键,在弹出的菜单中选择【获取网络模板列表】”;

第二步:在现金缴款单列表中选中“农业银行现金缴款单”并点击右键;

第三步:在弹出的菜单中选择【下载模板到本地】即可。

模板添加完成。

您可以进行打印偏移设置,然后使用了。

如何进行偏移设置


第一步:将票据按如图所示紧贴打印机的左边缘进纸。


第二步:选中票据,点击“设计模式”按钮,然后点击“打印”按钮打印票据。


第三步:测量打印内容向上移动与向左移动的距离。精确到0.1毫米”))


第四步:单击“偏移设置”按钮,将测量的值(单位:厘米)填入,确定。


设置完成。单击“设计模式”按钮,退出设计模式。尽情打印票据吧!

用户评论


我最喜欢的就是《打印专家》打印出来的现金支票,太漂亮了!

重庆 丁    莉

简单得令人难以置信。

北京 蔡俊杰

收据打印功能太方便了!

云南 张国庆
0

如何定制新的银行票据

  • 如何定制新的银行票据
  • 以现金支票为例
  • 我们要添加一张“民生银行”的现金支票。
  • 首先准备好一张“民生银行现金支票”的扫描图片。
  • 鼠标点击导航视图中的“票据”标签,
  • 在展开的票据树形列表中点选“现金支票”。
  • 然后点击鼠标右键
  • 在弹出的菜单项中选择“新建”
  • 点击对话框上的“打开”按钮,
  • 选择新票据的图片。
  • 选择对话框里的模板来源参数,这里选择默认值。
  • 输入票据的名称,民生银行现金支票。
  • 确定。
  • 现在在树形列表中现金支票下面多了一个项目:
  • “民生银行现金支票”
  • 选中它,然后点选工具栏上的“设计模式”按钮
  • 可以看到:这个支票和刚才用的建设银行现金支票的差别不大,
  • 现在只需要进行一些微小的调整就可以了。
  • 打开工具栏上的“数据锁”图标,然后利用鼠标对模板进行修改。
  • 修改完毕,点击工具栏上的“数据锁”图标将锁关上,
  • 点击工具栏上的“设计模式”按钮退出设计模式。
  • 新的银行票据就定制好了。
    时长: 02分14秒

如何定制自己的模板

  * 如何定制自己的模板。 * 我们以“付款凭证”模板定制为例。 * 首先,将自己使用的“付款凭证”扫描成一张图片。 * 点击工具栏上的“设计模式”按扭,进入模板设计模式。 * 再将工具栏上的“数据锁”打开,以便对当前模板进行修改。 * 点选鼠标右键,选择弹出菜单中的“更改模板图片”菜单项, * 然后选择我们扫描好的图片。 * 确定。模板图片就改好了。 * 由于模板图片变化了,项目是没有对齐的。 * 我们可以通过鼠标拖动与拉伸改变每个项目的大小与位置,使它与新的模板图片保持一致。 * 修改好了,再把“数据锁”关上,并退出“设计模式”。 * 付款凭证模板的定制就完成了。 时长: 01分33秒

如何添加修改与删除

* 如何添加、修改与删除。 * 我们以付款凭证为例 * 点选“导航视图”中的“单据”标签 * 在单据树形列表中选择“付款凭证”。 * 点击右边工具栏上的“加号”图标按钮,即可添加一张新的凭证。 * 点击右边工具栏上的”减号”图标按钮,即可删除凭证。 * 如果减号图标按钮为灰色,则表明当前显示的凭证是往期的凭证, * 往期凭证是不能随便删除或修改的, * 如果确实需要修改或删除,则必须先将上方工具栏中的“数据锁”按钮打开。 * 点选工具栏上的“数据锁”图标将锁打开, * 这时,鼠标指针变成了铅笔,就可以对它进行修改或删除了。 * 往期数据修改完毕请再点击工具栏上的数据锁,把锁关闭。 时长: 01分29秒

如何调整项目的属性

* 如何调整项目的字体大小 * 我们以付款凭证为例 * 点选导航视图中的单据标签,在单据树形列表中点选付款凭证 * 点选工具栏上的“设计模式”按钮,进入设计模式 * 由于我们要对当前模板进行修改,所以请再点工具栏上的“数据锁”图标,将锁打开 * 我们要将“贷方科目”显示的文字调整一下 * 点选贷方科目 * 这时,右边属性栏里就会出现贷方科目相关的设置 * 选中字体,点击字体行后面的小按钮, * 在弹出的字体对话框中选择合适的字体。 * 点击“确定”按钮。 * 项目的字体调整就完成了。 * 设置完成请分别点击工具栏上的“数据锁”与“设计模式”按钮将锁关上并退出设计模式。 时长: 01分44秒