现代C++神器之variant

看过这两年的Cppcon都应该对variant印象深刻。这个东东不算新,2002年就有了boost::variant

说到variant就得提enumunionunion对非C系编程者可能有点陌生。按照当代角度,enum和union很大一部分作用在于缩减定义域。举例如下:

//choose one implementation below
enum OneTwoTree { ONE, TWO, TREE };
//
union OneTwoTree {
  int ONE;
  int TWO;
  int TREE;
};
//
void foo(OneTwoTree ott);

这里用OneTwoTree限制了相关领域的类型范围,比如说调用foo(4)时编译器就会报错。 Continue reading 现代C++神器之variant

尝试实现《Puyo Puyo》(1)

Puyo Puyo(魔法气泡)可能是我最喜欢的消除类游戏。规则很简单,超过四个方块连起来就会消除。如果结构设计良好,就会引发连锁反应。

13年对战纪念图

右边的结构,左下角黄色块引爆(就是消除,我习惯用引爆)之后,接着会引爆蓝色,接着引爆红色,蓝,红,绿,黄,蓝,红。左边的结构类似,当黄色块落下时会引爆11次,俗称11连锁。对我来说,这个游戏的乐趣就在于尽可能设计连锁最多的结构。 Continue reading 尝试实现《Puyo Puyo》(1)

现代C++神器之comma operator

comma operator也就是逗号。常见的用法不过是以下几种:

int a = 1, b = 2, c = 3;
foo(a, b);
tuple<int, float> t{1, 2.f};

这能有什么独特技巧?接着探索:

int a = 1;
int b = 2;
int c = a, d;
int e = (a, b);

第三行已经有点模糊,展开会比较清晰:

int c = a;
int d;

重点来了,第四行会发生什么? Continue reading 现代C++神器之comma operator

C++之无聊小技巧三.1

上文讨论了一工厂和访问者,为了贯彻娱乐精神,我们接下来组合这两个机制,看能搞出什么花样?

struct WidgetVisitor {
  virtual Widget *createNut(Nut &nut) = 0;
  virtual Widget *createBolt(Bolt &bolt) = 0;
};
struct Bolt : Widget {
  void accept(WidgetVisitor &v) { v.createBolt(*this); }
};
struct Nut : Widget {
  void accept(WidgetVisitor &v) { v.createNut(*this); }
};
struct WidgetFactory : WidgetVisitor {
  Widget *createNut(Nut &nut) { return new Nut; }
  Widget *createBolt(Bolt &bolt) { return new Bolt; }
};

使用的时候是这样:

Nut nut;
Bolt bolt;
WidgetFactory wc;
Nut *pNut = bolt.accept(wc);
Bolt *pBolt = nut.accept(wc);

哈哈,是不是有一种想打人的冲动?这也正体现本文的关键字——无聊。 Continue reading C++之无聊小技巧三.1

现代C++神器之literals

Modern C++有很多理念极具启发性。我个人很欣赏std::chrono::duration的设计,比如说它的构造方式:

milliseconds t1(15);
hours t2 = hours(2);
auto t3 = hours(10);
milliseconds t4(minutes(2));
milliseconds t5 = hours(1);

上面几种都是普通的初始化,后两个会转换不同格式的数据。但是呢:

minutes t6 = 14min;
hours t7 = 2h;

这又是什么?为什么编译通过?那两个后缀竟然合法?不仅如此:

auto t8 = 12s;
milliseconds t9 = 3min;

这两个也是合法的。 Continue reading 现代C++神器之literals

C++之无聊小技巧三

上一篇扯了一点设计模式,本文接着讨论。以下内容仅供娱乐。

先看一个朴实的例子:

struct Widget {};
struct WidgetManager {
  Widget *getWidget() {
    Widget *pw = this->createWidget();
    widgets.push_back(pw);
    return pw;
  }
private:
  virtual Widget *createWidget() { return new Widget; }
  vector<Widget *> widgets;
};
struct Bolt : Widget {};
struct BoltManager : WidgetManager {
  Widget *createWidget() { return new Bolt; }
};

Continue reading C++之无聊小技巧三

C++之无聊小技巧二

接下来扯一点设计模式。一般的业务框架会包含大量的模板方法模式,它的目的主要是为了复用代码。看个简单例子:

struct SessionManager {
  void execute() {
    open();
    run();
    close();
  }
private:
  void open() { cout << "session start" << endl; }
  void close() { cout << "session end" << endl; }
  virtual void run() { cout << "run" << endl; }
};
struct Printer : SessionManager {
  void run() { cout << "print ABC" << endl; }
};
int main() { 
  SessionManager *a = new Printer(); 
  a->execute();
/*
print: 
  session start
  print ABC
  session end
*/
}

Continue reading C++之无聊小技巧二

C++之无聊小技巧

通用编程语言的基本特性都相差不远,同时也各有各的玩法。C++特性之多首屈一指,各种其他语言看不到的玩法,当然其实用性也有限。本文简单探讨一些无聊并有趣的技巧,特性或者Idiom。演示这些的目的在娱乐,并不建议在工程中使用。

诊断

C语言本身就有assert(),不过没有输出信息。C++11又加上static_assert(),支持输出信息。
在这之前可以自己实现带输出的诊断:

#define m_assert(condition, message){ \
  if ( !(condition) ) {  \
    print("Assertion failed:", message);  \
    exit(-1); \
  }  \
}  \

或者这样:


assert(condition && message)

Continue reading C++之无聊小技巧

吃饱了撑的之实现drop函数?

本篇的灵感如题来自一个常见的函数drop(),他的用法是这样的:

vec{1, 2, 3, 4, 5}
vec1 = drop(2, vec) // vec1 = {3, 4, 5}
vec1 = drop(-1, vec) // vec1 = {1, 2, 3, 4, 5}
vec1 = drop(7, vec) // vec1 = {}

它在函数式或者动态语言里非常常见。一般实现是这样:

drop = (n, xs) => {
    if (n <= 0 || xs === [])
        return xs
    else 
        return drop(n - 1, tail(xs))
}

这里借助了tail()。如果用Python或者Go就是xs[1:](尾递归优化不在探讨范围)。 Continue reading 吃饱了撑的之实现drop函数?

C++,STL的小故事

一位逻辑学家Robert Kowalski说过Algorithm = Logic + Control。什么是Logic?什么又是Control?其实就是业务逻辑和控制流。

大多情况下,我们要简化的流程就是循环。有个理念叫“no raw loop”,不是说禁止你用for loop,而是将循环流程封装起来,只在业务层暴露抽象算法接口。《Effective STL》中也有过类似探讨——Item 43. Prefer algorithm calls to hand-written loops

Continue reading C++,STL的小故事