C++ 的 idioms(十五)

safe bool

如果对 operator bool 进行简单的重载,可能导致一些奇怪的 code 是合法的。有一些合理的 hack,见这里

#include <iostream>
int main (int, char**) {
  if (std::cout != std::cin)
    std::cout << std::cin << std::cerr
              << std::clog << std::cout
              << std::endl ;
  return 0 ;
}

为此,核心思想就是传一个不是 bool 的类型,但是它可以转换成 bool,比如指针;为了避免他们之间的比较,必须是每类自己独有的一个东西,他们之间默认是无法比较的。这个可以用成员函数的指针获得。下面是 wikibooks 一个简单的例子。

class testable {
  bool ok_;
  typedef void (testable::*bool_type)() const;
  void this_type_does_not_support_comparisons() const {}

public:
  explicit testable (bool b=true) : ok_(b) {}

  operator bool_type() const {
    return ok_==true ?
      &testable::this_type_does_not_support_comparisons : 0;
  }
};

利用 CRTP 可以写成一个 reusable 的 pattern。这个相当于在 base 里面提供 operator 转换到以上类型,要求子类实现对应的 test 函数。

scope guard

是对 RAII 的增强,在于提供了一个 bool 表示对 resource 的控制是否终结

class resource {
  bool own ;
public:
  resource () : own (true) {
    // initialize resource
  }
  ~resource () {
    if (own) {
      // release resource
    }
  }
  void release () {
    own = false ;
  }
} ;

smart pointer

这个大家都比较熟悉了。std::auto_ptr 或者 boost::shared_ptr 等等。

tag dispatching

是一个常用的技术(最早的相关 blog 见这里),应用场景是在为一系列 concept 的实现提供不同实现的优化,前提是每个实现都包含某个 tag 用于区分。tag 本身可以继承,表示 concept 的 refinement 关系。一般举例都是 STL 的各种 iterator 的优化。这里举个简单的例子,比如我们有一些鸭子,有的鸭子左翅可以挥动,有的鸭子右边可以,还有两只都能动的。这样我们实现的 policy 大致是下面的样子。

struct left_tag {} ;
struct right_tag {} ;
struct both_tag : left_tag, right_tag {} ;

struct left_policy {
  void left () ;
} ;
struct right_policy {
  void right () ;
} ;
struct both_policy : left_policy, right_policy {
} ;

这样很多鸭子或者是能用左手的,或者是能用右手的,或者是两只手都能用的。现在我们需要写一个鸭子的 fly 训练过程。于是可以先为这三种分别实现对应的 training 函数,它们根据提供的方法进行调用。为了区分这些鸭子,我们强制传入一个 tag,用来标识这是个什么样子的鸭子,比如

template <class Duck> void
training_imp (Duck&, right_tag) {
  // do things with right()
}

然后我们的鸭子和 facade 是这样的:

class chinese_duck : both_policy {
  typedef both_tag tag ;
  // ...
} ;

template <class Duck> void
training (Duck& d) {
  training_imp (d, typename Duck::tag) ;
}

这样就能为特定的鸭子使用不同的 training procedure 了。这要求能够修改 duck 本身的 typedef,否则就需要使用 traits。这个 facade 将 tag dispatch 到不同的实现上,获得了静态的 polymorphism。tag dispatch 允许将很多完全接口不同的东西 bind 到一个统一的 interface 之上,但是对实现来说可能就得为每种 tag 实现不同策略。但是某些时候也不尽然,比如前面如果我们仅仅实现了 left_tag 的 training_imp,其实 both_tag 的鸭子也是可以参与的,因为 both_tag 可以隐含的转换到 left_tag 上。

temporary base class

是优化临时变量的一种方法,在两个 A 类型的运算的时候返回 B 类型的结果,B 类型可以与 A 类型继续操作下去,但是只是返回 B 自己的引用,这样一来 B 其实不必要被释放,可以继续和后面的操作进行下去,如此一来就避免了不必要的释放。但是感觉这样仍然是一种比较弱势的优化,如果用户增加了括号,也会产生 B 的额外对象,然后出现 B 与 B 的操作。这样一方面增加了 code 的开销,另一方面似乎也没减少很多 cost,不如 expression template 快捷。具体的例子参考 wikibooks。

——————
And he took to him all these, and divided them in the middle, and laid each piece one against another: but the birds divided he not.

Advertisements
C++ 的 idioms(十五)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s