c++備忘錄

#1.模板類的模板成員函數

template <typename type1>

class C {

public:

template <typename type2>

void f();

}

如果需要在類外定義函數f時,要這樣寫:

template<typename type1, typename type2>

void C<type1>::f() {...}

而不能寫成

template<typename type1>

template<typename type2>

void C<type1>::f() {...}

#2.宏定義中的“#”,“##”,“#@”用法

“#”用於將宏參數轉化爲字符串,即在宏參數的兩邊加上雙引號。例如:

#define STR(x) #x
int abc = 1;
cout << STR(abc) << endl;

上面會輸出程序會將會輸出字符串“abc”而不是變量abc的值。

“##”用於宏參數之間的連接或宏變量與其他代碼的連接。例如:

#define VAL1(x) x##1
#define VAL2(x, y) x##y
int abc1 = 1;
cout << VAL1(x) << endl;
cout << VAL2(x, 1) << endl;
兩個輸出語句都會輸出變量abc1的值。

“#@”是將宏參數轉成字符,即在宏參數的兩邊加上單引號,不過gcc不支持。

在使用“#”,“##”,“#@”時,如果宏參數本身也是宏的話,該宏參數是不會進行宏展開的,這裏用一個簡單的例子解釋下:

#define STR(x) #x
cout << STR(__LINE__) << endl;
上面的代碼並不會將宏__LINE__展開,因此得到的輸出是“__LINE__”,而不是當前代碼行號的字符串表示。爲了能夠將__LINE__展開,我們需要藉助轉換宏。
#define _STR(x) #x
#define STR(x) _STR(x)
cout << STR(__LINE__) << endl;
這樣宏__LINE__就會在調用STR的時候展開,因此傳給_STR的就是__LINE__的值了。


#3. 匿名命名空間

匿名空間中定義的函數或變量的作用域被限制在文件範圍內,功能等同於用static修飾這些函數或變量。例如:

#a.cpp
void f1(){...};
static void f2(){...};
namespace {
  void f3(){...};
}
#b.cpp
extern void f1(); //ok
extern void f2(); //鏈接出錯
extern void f3(); //鏈接出錯


#4. 內聯命名空間(c++11)

當父命名空間中定義了一個嵌套的普通命名空間時,訪問該嵌套命名空間中函數或變量等時需要使用域作用符。但當該嵌套命名空間換成一個內聯命名空間時,該內聯命令空間中的函數或變量等自動成爲父命名空間的成員,訪問時不需要域作用符。版本控制場景下可能會需要這個特性,下面舉個例子說明:

namespace Pro {
  namespace v1 {
    void f1();
    void f2();
  }
  inline namespace v2 {
    void f1();
  }
}

當你的項目版本1提供兩個函數f1和f2,但版本2修改f1並且去掉了f2,這時你如果調用Pro::f1那麼調用的函數是內聯命名空間v2中的f1,並且調用Pro::f2會報錯,如果你確實需要用到老版本中的函數,你可以這樣調用:Pro::v1::f1和Pro::v1::f2。

#5.對齊

編譯器中提供了#pragma pack(n)來設定變量以n字節對齊方式。n字節對齊就是說變量存放的起始地址的偏移量有兩種情況:第一、如果n大於等於該變量所佔用的字節數,那麼偏移量必須滿足默認的對齊方式,第二、如果n小於該變量的類型所佔用的字節數,那麼偏移量爲n的倍數,不用滿足默認的對齊方式。結構的總大小也有個約束條件,分下面兩種情況:如果n大於所有成員變量類型所佔用的字節數,那麼結構的總大小必須爲佔用空間最大的變量佔用的空間數的倍數;否則必須爲n的倍數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章