posts - 13, comments - 4, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Exceptional C++ Style 读书笔记(三)

Posted on 2008-11-06 23:30 Batiliu 阅读(341) 评论(0)  编辑 收藏 引用 所属分类: 读书笔记

第三十二条 奇形怪状

下面程序的输出是什么?

#include <iostream>
 
int _tmain(int argc, _TCHAR* argv[])
{
    int x = 1;
 
    // 下面这行代码你确认在递增吗??/
    ++x;
 
    std::cout << x << std::endl;
 
    return 0;
}

“输出 2”,如果你无须思索的回答道。那么,恭喜你。。。。答错了。不相信?请你将这段程序一字不差的复制到Visual Studio中(本人环境VS2008),然后Ctrl+F5,正确答案会立即显示在眼前:输出居然是 1!

 

最好在你亲自试验了后,我们来一起揭晓原因:

注意到“// 下面这行代码你确认是递增吗??/”这行注释了吗?注释中结尾的“??/”会被转换成“\”,而后者放在一行的末尾作用相当于将接下来的一行“粘贴”到这一行的末尾!这太令人诧异了!本例中,它将接下来的“++x”粘贴到了注释行的末尾,这样“++x”就成了注释的一部分,不会被实际实行了。

为什么会这样?因为C++从C语言继承了一个“三字符组”的特性。所谓三字符组(trigraph)是指三个字符组成的转义符,比如“??/”=“\”,“??!”=“~”等。

 

风格案例研究

 

以下代码展示了在已有容器中创建索引表的一种惯用法。

// 代码展示:索引表
#include <vector>
#include <map>
#include <algorithm>
 
// Solution1
 
namespace Solution1 {
    template<class Iter>
    class sort_idxtbl_pair {
    public:
        void set(const Iter& it, int i) { it_ = it; i_ = i; }
        bool operator<(const sort_idxtbl_pair& other) const
        { return *it_ < *other.it_; }
        operator int() const { return i_; }
    private:
        Iter it_;
        int i_;
    };
 
    template<class IterIn, class IterOut>
    void sort_idxtbl(IterIn first, IterIn last, IterOut out) {
        std::vector<sort_idxtbl_pair<IterIn> > v(last - first);
        
        for (int i = 0; i < last - first; ++i)
            v[i].set(first + i, i);
 
        std::sort(v.begin(), v.end());
 
        std::copy(v.begin(), v.end(), out);
    }
}
 
// Solution2:使用std::pair而不是重新发明一个类似pair的辅助类。
namespace Solution2 {
    template<class T, class U>
    struct ComparePair1stDeref {
        bool operator()(const std::pair<T,U>& a, const std::pair<T,U>& b) const
        { return *a.first < *b.first; }
    };
 
    template<class IterIn, class IterOut>
    void sort_idxtbl(IterIn first, IterIn last, IterOut out) {
        std::vector<std::pair<IterIn, int> > s(last - first);
        for (int i = 0; i < s.size(); ++i)
            s[i] = std::make_pair(first + i, i);
 
        std::sort(s.begin(), s.end(), ComparePair1stDeref<IterIn,int>());
 
        for (int i = 0; i < s.size(); ++i, ++out)
            *out = s[i].second;
    }
}

测试用例:

#include <iostream>
 
int _tmain(int argc, _TCHAR* argv[])
{
    int a[10] = {8, 9, 1, 3, 5, 7, 6, 4, 2, 0};
    std::vector<int> idxtbl(10);
 
    Solution2::sort_idxtbl(a, a + 10, idxtbl.begin());
 
    for (int i = 0; i < 10; ++i)
        std::cout << "i = " << i 
                << ", idxtbl[i] = " << idxtbl[i]
                << ", a[idxtbl[i]] = " << a[idxtbl[i]]
                << std::endl;
 
    return 0;
}

以下代码展示了一个用于外覆回调函数的惯用手法。

class CallbackBase {
public:
    virtual void operator()() const {};
    virtual ~CallbackBase() = 0;
};
 
CallbackBase::~CallbackBase() {}
 
template<typename T>
class Callback : public CallbackBase {
public:
    typedef void (T::*F)();
 
    Callback(T& t, F t) : t_(&t), f_(f) {}
    void operator()() const { (t_->*f_)(); }
 
private:
    T* t_;
    F  f_;
};
 
template<typename T>
Callback<T> make_callback(T& t, void(T::*f)()) {
    return Callback<t>(t, f);
}
 
你需要支持const成员函数?支持非void类型的返回值?支持不同参数类型或数目的回调函数?别急、别急,敬请期待我即将发布的《基于C++的多播委托》,如果你实在等不及,Loki库的'functors'将为你带来顶级大师的盛宴。
 

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理