C++ 有哪些鮮為人知的奇特操作?
C++一直是公認比較難以精通的語言,那它有哪些讓人覺得「哇靠,還可以這樣!」的奇特操作呢?
stateful meta-programming 算一個。
C++ 的 stateful meta-programming 這麼強大,為什麼沒見有什麼庫用?C++: Adding and redefinition of default arguments in real world
這功能還沒死,甚至沒有deprecated,也是驚人。
別用。
void foo(int a, int b, int c = -1) {
std::cout &<&< "foo(" &<&< a &<&< ", " &<&< b &<&< ", " &<&< c &<&< ")
";
}
int main() {
foo(1, 2); // output: foo(1, 2, -1)
// error: does not use default from surrounding scope
//void foo(int a, int b = 0, int c);
void foo(int a, int b, int c = 30);
foo(1, 2); // output: foo(1, 2, 30)
// error: we cannot redefine the argument in the same scope
// void foo(int a, int b, int c = 35);
// has a default argument for c from a previous declaration
void foo(int a, int b = 20, int c);
foo(1); // output: foo(1, 20, 30)
void foo(int a = 10, int b, int c);
foo(); // output: foo(10, 20, 30)
{
// in inner scopes we can completely redefine them
void foo(int a, int b = 4, int c = 8);
foo(2); // output: foo(2, 4, 8)
}
return 0;
}
- 函數和變數的聲明寫法可以統一。函數的「變數」類型,就是函數自身的類型。它不是函數指針。在元編程中處理成員指針時,以及hooking時有奇效。
class Foo
{
using func_t = void(int x, float y);
func_t myFunc;//函數
func_t* anotherFunc;//函數指針指向另一個函數
};
void Foo::myFunc(int x, float y){}
其他的想到了再添加...
前幾周跟個Google的同學聊天,碰到這個我覺得最騷的:
如何在對象初始化之前(構造函數執行之前)做一些騷操作(類似的問題:C++ - Run a function before initializing a class member)?好像是他們的測試框架裡面的代碼要這麼做,初始化一個const成員,但是初始化之前的賦值要調用一個什麼函數做一些類似notify的操作。
我當時能夠想到的方法是搞個基……類,然後在其構造函數裡面搞。但是這樣的方法顯然太髒了,還要專門引入一個類。然後他說他上網查了可以用逗號表達式,我當時震驚了,原來這TM也可以,先前沒想到這樣去用逗號表達式。
a = (5, 6, 7);
cout &<&< a &<&< endl;
輸出是7,因為逗號表達式從左往右執行,取最右值返回。
而且逗號表達式的操作符不一定是const,也可以是函數什麼的,所以只需要在初始化列表裡面搞個逗號表達式,把要執行的函數丟在左邊就好了。
最近跟人討論,有人很鄙視這種技巧,說是什麼know-how、炫技、不是正道……呃,在工程里你要達到一個目標,這些技巧雖然非常少見,也不提倡使用,但是如果它是解決問題的最優方法,那能不用么?難道非得為了用「正統」寫法把程序重構一遍么?那是作死啊。
通過檢查類型是否具有指向成員的指針來判斷一個類型是不是類類型...
struct True{
char x;
};
struct False{
char x[2];
};
template&
struct IsClass{
template&
template&
enum{RESULT=sizeof(IsClass&
};
int main()
{
if(IsClass&
cout&<&<"yes"&<&
delete this;
typeid來做類型擦除後的恢復;
=====
還有一個是ide相關的,可以在編譯開始前執行某個可執行程序,可以替換或者產生新的代碼並加入到編譯鏈中。QT和ue4都是靠這玩意實現反射。
SFINAE,很常用的特性讓c++用起來非常爽。但我想說,這騷特性經常是讓人騷操作一通後突然一悶棍打醒,「我是誰」「我在哪」「我在做什麼」
暫時先想到一個,intrusive list,這個有些場合很有用。是不是鮮為人知就不知道了,有人跳出來說老子第一天用C++編程就知道這個也說不定呢。
如果你不熟悉C++,那麼C++很多操作都很詭異。如果你熟悉C++,那麼C++只是很瑣碎,有時候不直接,但是並沒有什麼離奇的內容。
C++一樣可以做到C那樣的彈性數組,
代碼來自Google的leveldb,
template&
struct SkipList&
// 省略中間的代碼
private:
// Array of length equal to the node height. next_[0] is lowest level link.
port::AtomicPointer next_[1]; // 注意!
};
這裡的next_[1], 其中1是虛指的, 只是因為C++不允許next_[]或者next_[0].
實際構造是這樣的,
template&
typename SkipList&
SkipList&
char* mem = arena_-&>AllocateAligned(
sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); // 注意
return new (mem) Node(key);
}
依靠內存布局完成了C中的彈性數組.
但我沒明白new(mem) Node(key)為什麼要這麼寫,
it works...
不知道是不是鮮為人知,用raii實現go語言里的defer語句,這個非常實用。http://mindhacks.cn/2012/08/27/modern-cpp-practices/
A a;
a.~A();
預處理命令不好好用就成了……
推薦閱讀: