C++ 杂谈(9)

__VA_ARGS__

这是一个神奇的 macro,通过它能做到很多不可以想象的事情,简而言之定义 macro 的参数的时候通过它可以定义变长参数,

#define MY_MACRO(...) printf(__VA_ARGS__)
MY_MACRO("abc: %d", i);

GCC 的版本跟一般略有不同。标准下一旦有了多于一个参数以上就不 work 了

#define MY_MACRO(format, ...) printf(format, __VA_ARGS__)
MY_MACRO("abc: %d", i);

这里如果 … 对应的是 0 个参数 printf 就会多出来一个 , 而这个会导致编译器出错。一个解决方案是使用 ##__VA_ARGS__ 它会在 __VA_ARGS__ 为空的时候吃掉最后的逗号。参看这里

但是更神奇的一个用法是和 lambda 结合起来:我们知道定义一个 lambda 需要 [] 部分、() 和 {},一旦将其赋值给一个变量,我们就可以通过 decltype 获得这个 lambda 的返回值类型,这样一来我们可以在另一个 lambda 分离的 scope 里面定义需要的类型,并通过这个 lambda 返回我们生成的类型

#define INLINE_FOO(...) \
  []() { \
    auto func = [] __VA_ARGS__;
    typedef decltype(func) func_type;
    struct LocalFoo : public Foo {
      // implement LocalFoo with __VA_ARGS__
    };
    return LocalFoo(); // or new LocalFoo()
  }()

这种结构可以极大的方便一些“即兴”需要的实现。

template 参数作为 friend

这也是一个 C++11 的特性,之前不允许 template 的参数作为 friend,现在可以如下使用

template <typename T>
class Foo {
public:
  friend T;
};

异常

一个语言处理“错误”往往有很多种选择,早期的 C 使用的策略是一种非常简单的策略:

  • 函数可以返回不合理的值,这样 caller 就有一个检查返回值的机会
  • 函数可以设计一种 protocol,比如函数输入输出必须都通过函数参数传递,这样返回值永远是 bool/int 或者 void,出错后什么都不做或者返回 false 或非 0,void 通常通过全局变量表示出错信息

不论怎么做其实对调用者来说都是一种 burden,前者可能稍微好一点,后者必须先创建返回的对象,但是两者都必须 on spot 处理出错的问题(或者忽略出错继续,这可能导致不能预见的事情发生,这特别在某些反或正常值又设置了 errno 的函数),有时候尽管会提供一些 macro 来减缓这类 boilerplate code,但是不能否认我们不能避免在“不必要处理问题”的时候处理问题,往往那些处理的代码也就是打印 call stack 退出。某些 code 可能会提供一个 error handler 的接口给用户供用户在出错后决定如何处理。functional programming 常用 Try 这类 monad 来做,但是这个 pattern 就像瘟疫一样会传播到整个调用函数栈,一般来说我们还是希望把这个处理做得越简单越好。特别的,对 C++ 的哲学来说,不使用就不应该造成额外的负担。

在 C++ 实现其 exception handling 的时候尤为注重这一点,之前讨论了 gcc 实现异常的基本原理 two-phase scanning,这个保证了不使用不造成额外负担的特性。

——————
And it came to pass on the third day, when they were sore, that two of the sons of Jacob, Simeon and Levi, Dinah’s brethren, took each man his sword, and came upon the city boldly, and slew all the males

Advertisements
C++ 杂谈(9)

发表评论

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