C++ 有哪些奇技淫巧?

越喪病越好


。。。下面這些技巧並非 C++ 獨有。。。。

1. 內嵌彙編

我們知道 C++ 中可以使用

#pragma comment(linker, "/STACK:36777216")

改變棧空間的大小。但在 G++ 中。。上面的方法並不奏效。

在 G++ 中。。可以使用下面的代碼。。。改變棧空間的大小。。。

int __size__ = 256 &<&< 20; // 256MB char *__p__ = (char*)malloc(__size__) + __size__; __asm__("movl %0, %%esp " :: "r"(__p__));

。內嵌彙編還可以優化一些底層函數。。得到可觀的效率提升。。。

例如下面這種計算 x * y % MOD 的函數。。。

inline int pdt(int x,int y) {
int ret; __asm__ __volatile__ (" mull %%ebx
divl %%ecx
":"=d"(ret):"a"(x),"b"(y),"c"(MOD));
return ret;
}

我們之前在某個 Go 語言的工程中。。就通過內嵌 C 語言優化底層的模塊。

得到效率的可觀提升。。。。原理是一致的。。

2. 並發優化

在 Codechef 2012 Nov Challenge 的 Arithmetic Progressions 一題中。。

Roy Palacios Rezza 使用了下面看似樸素的代碼秒殺了所有正解。。

拿到了代碼長度和運行效率的 Rank I。。。

Solution | CodeChef

題意:

"給定一個長度為 n 數列 {an},求所有滿足 i &< j &< k,且 a[j] - a[i] = a[k] - a[j] 的三元組數。。"

( n &<= 1e6, 1 &<= ai &<= 3e4 .. . )

tmp += (*p1) * (*p2) + (*(p1+1)) * (*(p2+1)) + (*(p1+2)) * (*(p2+2)) + (*(p1+3)) * (*(p2+3)) + (*(p1+4)) * (*(p2+4))
+ (*(p1+5)) * (*(p2+5)) + (*(p1+6)) * (*(p2+6)) + (*(p1+7)) * (*(p2+7)) + (*(p1+8)) * (*(p2+8)) + (*(p1+9)) * (*(p2+9))
+ (*(p1+10)) * (*(p2+10)) + (*(p1+11)) * (*(p2+11)) + (*(p1+12)) * (*(p2+12)) + (*(p1+13)) * (*(p2+13)) + (*(p1+14)) * (*(p2+14));

這段代碼刺激了 CPU 的並發優化。。使得效率得到了常數級的提升。。。

類似的技巧還出現在了 CF #472 G 中。。

Submission #8007736 。。。

為什麼大家都知道?!


沒人說這個么?

template & struct D { D(void*); operator int(); };

template & struct is_prime {
enum { prim = (p==2) || (p%i) is_prime&<(i&>2?p:0), i-1&> :: prim };
};

template & struct Prime_print {
Prime_print& a;
enum { prim = is_prime&::prim };
void f() { D& d = prim ? 1 : 0; a.f();}
};

template&<&> struct is_prime&<0,0&> { enum {prim=1}; };
template&<&> struct is_prime&<0,1&> { enum {prim=1}; };

template&<&> struct Prime_print&<1&> {
enum {prim=0};
void f() { D&<1&> d = prim ? 1 : 0; };
};

#ifndef LAST
#define LAST 18
#endif

int main() {
Prime_print& a;
a.f();
}

在編譯錯誤輸出種你能找到小於LAST的所有質數。

clang編譯後輸出如下:

x.cpp:12:17: error: no viable conversion from "int" to "D&<17&>"
..... //略過幾十行
x.cpp:12:17: error: no viable conversion from "int" to "D&<13&>"
..... //略過幾十行
x.cpp:12:17: error: no viable conversion from "int" to "D&<11&>"
..... //略過幾十行
.....


class Player : public dodo::rpc
{
public:
Player()
{
registerHandle("player_attack", Player::attack);
registerHandle("player_hi", Player::hi);
}

private:
template&
void registerHandle(string name, void (Player::*callback)(Args...))
{
def(name.c_str(), [this, callback](Args... args){
(this-&>*callback)(args...);
});
}

private:
void attack(string target)
{
cout &<&< "attack:" &<&< target &<&< endl; } void hi(string i, string j) { cout &<&< i &<&< j &<&< endl; } }; Player rpc_server; /*rpc伺服器*/ Player rpc_client; /*rpc客戶端*/ rpc_request_msg = rpc_client.call("player_attack", "Li Lei"); rpc_server.handleRpc(rpc_request_msg); rpc_request_msg = rpc_client.call("player_hi", "Hello", "World"); rpc_server.handleRpc(rpc_request_msg);

執行結果:

attack:Li Lei

HelloWorld

~發現了一個wiki:More C++ Idioms各種C++奇技淫巧。


奇技淫巧怎能不提宏:

有時候想寫一個可變參數宏,然後宏會以"__VA_ARGS__"來代表那一堆參數,可是C/C++居然沒有

提供代表可變參數的個數的東西,因此有大神發明了以下代碼:

//獲取宏內參數的個數

#define Y_TUPLE_SIZE_II(__args) Y_TUPLE_SIZE_I __args
#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0

#define Y_TUPLE_SIZE_I(__p0,__p1,__p2,__p3,__p4,__p5,__p6,__p7,__p8,__p9,__p10,__p11,__p12,__p13,__p14,__p15,__p16,__p17,__p18,__p19,__p20,__p21,__p22,__p23,__p24,__p25,__p26,__p27,__p28,__p29,__p30,__p31,__n,...) __n

#define MPL_ARGS_SIZE(...) Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))

//---------------------------------------

MPL_ARGS_SIZE(a,b,c,d,e,f,g)==7

MPL_ARGS_SIZE(a,b,c,d)==4

第一次看見時很困惑,研究之後,給那個逗號遞歸跪了.....


C++ template programming: Embedding the lambda-calculus to show Turing-completeness

Open pattern matching for C++


struct x struct z&&v&

請用g++編譯。


http://pfultz2.github.io/Fit/doc/html/infix/

在C++里定義新的操作符。假如你有個函數add_f(x, y),定義infix_adaptor& add;

然後你就可以寫x=1 & 2

不算什麼太詭異的東西,只是覺得挺好玩。


隨便寫幾個思考題:

如何將lambda存到new出來的內存

如何實例化指數級個template&

如何用字元串做模版參數

如何將一個對象就地變換成另一個類的對象

如何檢測某個類是否有某個名字的成員

如何實現template virtual成員函數

如何實現動態multi dispatch

如何宕掉主流C++編譯器

……


跟 @邵成 和 @藍形參 提到的一致。

21天學通C++模版編程語言。-Kim Leo

21天學通C++模版編程語言。(下)-Kim Leo


%:include &

int main()
&<% bool arr&<:2:&> = &<% true and false or not true %&>;
return 0;
%&>

syntax - C++ alternative tokens?


(話說右值引用是不是C++獨此一家啊。。。)(純粹是為了擦屁股的存在吧!)

總感覺左值引用的轉換是在平時寫代碼中會用到的比較詭異的東西了。。。

不如前幾天犯傻以為void*可以和int做計算,等我反應過來的時候已經來不及了。。。

於是有了類似這樣的代碼:

void* p;

(char*)p += 2;

真實取材於某給別人寫的大作業。。。


是時候祭出大殺器了,出自 恐怖的C++語言

請看下面這段代碼,你能告訴我它會輸出什麼嗎?

#include &
#include &

typedef int UINT4;
using namespace std;
class Hack
{
};

Hack operator&< (Hack a , Hack b) { std::cerr &<&< "小於操作符 "; return a; } Hack operator&> (Hack a, Hack b)
{
std::cerr &<&< "大於操作符 "; return a; } int main(int argc, char ** argv) { Hack vector; Hack UINT4; Hack foo; vector& foo;
}


難道沒有人說SIMD硬體加速運算嗎?

體現了「C++是世界上最好的語言」

#include "stdafx.h"
#include &
#include &

int _tmain(int argc, _TCHAR* argv[])
{
__declspec(align(16)) float a[] = {1.5, 2.5, 3.5, 4.5};
__declspec(align(16)) float b[] = { 1.2, 2.3, 3.4, 4.5 };
__declspec(align(16)) float c[] = { 0.0, 0.0, 0.0, 0.0 };

__m128 m128_a = _mm_load_ps(a);
__m128 m128_b = _mm_load_ps(b);
__m128 m128_c = _mm_add_ps(m128_a, m128_b);

_mm_store_ps(c, m128_c);

for (int i = 0; i &< 4; i++) { printf("%f ", c[i]); } printf(" "); system("pause"); return 0; }


史前時代寫過這麼一篇東西:C中的自殺函數和C++中的自殺類

class TestClass
{
public:
TestClass();
protected:
private:
};

TestClass::TestClass()
{
printf("This is construct function./n");
delete this;
printf("And I have suicided ");
}

嚴禁吐槽我的英語有多爛……


用模板和宏定義設計一個內存泄露檢測機制:

#define TRACK_IDENTIFIER(x)
friend class allocation_trackable;
protected: static const char *_tracker_identifier() { return #x; }

static map& ALLOCATIONS;

void checkLeaks() {
bool leaks = false;
for(auto elem : ALLOCATIONS) {
if (elem.second != 0) {
cout &<&< elem.first &<&< " allocation not balanced, may cause leaks." &<&< endl; leaks = true; } } if (!leaks) { cout &<&< "Heap allocation clean, no leaks occurred." &<&< endl; } } template &
class allocation_trackable {
public:
allocation_trackable() {
const char *key = T::_tracker_identifier();
ALLOCATIONS[key] += 1;

cout &<&< T::_tracker_identifier() &<&< " allocated!!" &<&< endl; } virtual ~allocation_trackable() { ALLOCATIONS[T::_tracker_identifier()] -= 1; cout &<&< T::_tracker_identifier() &<&< " dealloced!!" &<&< endl; } };

用法很簡單,讓所有需要跟蹤內存申請的類繼承上面這個 `allocation_trackable` 父類,然後定義一個標識符即可:

class Foo : allocation_trackable& {
TRACK_IDENTIFIER(Foo)
};

然後盡情地 new 吧,想檢查內存溢出的時候只要停下程序或者加個斷點:

在調試窗口輸入命令:

是不是很方便呢。當然,方案不成熟,僅供娛樂~


1. Functor 為STL之基礎

2. Template-based meta-programming 就是Lisp而已,有什麼難懂的(目指Loki庫


局部函數(方法),類似pascal的,不知道有沒有人用


前幾天在boost.proto里看到一個有意思的。

struct dont_care { dont_care(...); };

struct private_type {

private_type const operator,(int) const;

};

typedef char yes_type; // sizeof(yes_type) == 1

typedef char (no_type)[2]; // sizeof(no_type) == 2

template&

no_type is_private_type(T const );

yes_type is_private_type(private_type const );

template&

struct funwrap2 : Fun {

funwrap2();

typedef private_type const (*pointer_to_function)(dont_care, dont_care);

operator pointer_to_function() const;

};

template&

struct can_be_called {

static funwrap2& fun;

static A a;

static B b;

static bool const value = (sizeof(no_type) == sizeof(is_private_type( (fun(a,b), 0) )));

typedef mpl::bool_& type;

};


在沒有關鍵字final的時候,C++可以通過友元和虛繼承實現出一個永遠無法派生出子類的class

C++來實現類似簡單的python tuple

namespace Utils
{
template& struct tuple;
template&<&> struct tuple&<&> {};
typedef tuple&<&> nulltuple;

template&
struct tuple& : public tuple&
{
typedef T value_type;
typedef tuple& base_type;

tuple() {}
tuple(value_type v, TList... tails)
: base_type(tails...), _value(v) {}
const value_type head() const { return _value; }
value_type head() { return _value; }
tuple& operator = (const tuple& _tuple)
{
if(_tuple == this) return *this;
_value = _tuple._value;
tuple&::operator = (_tuple);
return *this;
}

protected:
value_type _value;
};

template&
struct tuple& : public nulltuple
{
typedef T value_type;
typedef nulltuple base_type;

tuple() {}
tuple(value_type v) : _value(v) {}
tuple& operator = (const tuple& _tuple)
{
if(_tuple == this) return *this;
_value = _tuple._value;
return *this;
}

const value_type head() const { return _value; }
value_type head() { return _value; }

protected:
value_type _value;
};

template& struct tuple_at;
template&
struct tuple_at& &>
{
typedef typename tuple_at& &>::value_type value_type;
typedef typename tuple_at& &>::tuple_type tuple_type;
};

template&
struct tuple_at&<0, tuple& &>
{
typedef T value_type;
typedef tuple& tuple_type;
};

template&<&>
struct tuple_at&<0, nulltuple&>
{
typedef nulltuple value_type;
typedef nulltuple tuple_type;
};

template&
const typename tuple_at& &>::value_type
tuple_get(const tuple& _tuple)
{
typedef tuple& tuple_type;
typedef typename tuple_at&::tuple_type base_tuple_type;
typedef typename tuple_at&::value_type return_type;

return static_cast&(_tuple).head();
}
}


sizeof()不是一個函數。


推薦閱讀:

拷貝構造函數何時調用?
什麼是tlsf內存分配演算法? 它和普通的內存分配演算法有什麼區別?
C++派生類的成員或友員只能通過派生類對象來訪問基類的受保護成員?
變數名儲存在那裡,變數的儲存機制是什麼?
編程中你們都習慣怎麼使用大括弧?

TAG:C | X編程語言有什麼奇技淫巧 |