第三十二條 奇形怪狀
下面程序的輸出是什么?
#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'將為你帶來頂級大師的盛宴。