$ sudo apt-get remove --purge nouveau-firmware
$ sudo apt-get remove --purge xserver-
$ sudo apt-get install nvidia-current
在寫程式時,常常會需要計算一些數值, 而這些數值有可能在某些條件下是沒有意義的,例如我們要算一個數的平方根時,一定得先檢查此數是否為非負數,若為負數,則此取平方根是沒有意義的(當然若是運算有考慮虛數則例外)。這時我們的程式片段大概長這樣:
// double value = SOME_VALUE;
...
if (value>=0)
{
double sqrt_value = sqrt (value) ;
}
else
{
// error handling
}
這樣看起來其實沒什麼問題,但就設計哲學而言,client端 (sqrt函式的呼叫端) 必需先檢驗"條件",若通過後再真的"求值"。這樣的設計較為危險,因為 client必須去看文件,了解該函式的 domain 為何,再檢查 input 是否在該 domain 內,若是,再取值。把這樣的"知識"交由呼叫端來處理,可能帶來一些淺在的問題,例如呼叫端可能忘記檢查、可能檢查的條件是錯的,可能傳了負數進去得到了exception 卻沒處理,可能…。
Boost 提供了一個小小的 wrapper class template 名為 boost::optional 來處理這種無意義值。使用上很簡單,client 以要封裝的 type 為 optional 的 template 參數宣告一個物件,將條件及求值式傳入 constructor。然後我們可以把這個 optional 物件像是測試 NULL pointer 一樣檢查其有效性 (支援 implicit conversion to bool),再用 operator* 取值 (因為 override 了 operator*) 。
最後一步,就是在 library 端 (如果可以的話),或是 client 端寫個小小的 wrapper function 將條件封裝起來即可。
#include<boost/optional.hpp>
boost::optional<double> my_sqrt(double)
{
return boost::optional<double>(value>=0, sqrt(value));
}
void Foo( double value)
{
boost::optional<double> sqrt_value = my_sqrt( value );
if(sqrt_value)
{
cout << *sqrt_value << endl;
}
else
{
cout << "value should not be negative." << endl;
}
}
接著我們用 BOOST_AUTO 簡化一下程式碼,最後 client 就只要記得檢查 optional 是否有效,而不必知道如何檢查。
#include<boost/optional.hpp>
using namespace boost;
optional<double> my_sqrt(double)
{
return optional<double>(value>=0, sqrt(value));
}
void Foo( double value)
{
BOOST_AUTO( sqrt_value, my_sqrt( value ));
if(sqrt_value)
{
cout << *sqrt_value << endl;
}
else
{
cout << "value should not be negative." << endl;
}
}
有時我們需要對 STL container 大量的塞一些常數性質的資料,像是 error code 或是 event messages 之類的,以往就是在程式裡寫一堆 push_back 或 insert。
vector<int> v; v.push_back(1); v.push_back(3); v.push_back(4); v.push_back(7); v.push_back(9*9); map<int, string> m; m.insert ( make_pair ( 1, "one") ); m.insert ( make_pair ( 2, "two") ); m.insert ( make_pair ( 3, "three") );
Boost 的 assign 函式庫實作了 "operator+="、逗號 "," 及 括號 "operator( )" 來簡化這些操作,下例結果同上。
#include<boost/assign.hpp>
using namespace boost::assign;
vector<int> v;
v += 1, 3, 4, 7, 9*9;
map<int, string> m;
m += make_pair ( 1, "one"),
make_pair ( 2, "two"),
make_pair ( 3, "three");
使用 operator+= 在處理 map 時需要寫一大堆 make_pair,實在是很難看,我們可以用另一個 operator( ) 配合三個輔助函式insert( )、push_front( ) 及 push_back( ),更優雅地處理:
#include<boost/assign.hpp> using namespace boost::assign; vector<int> v; push_back(v)(1)(3)(4)(7)(9*9); map<int, string> m; insert(m)( 1, "one")( 2, "two")( 3, "three");
一般我們在寫 C++ 要用到 Boolean 值時,通常有兩種型別可以用:BOOL 及 bool。由於早期的 C++ 並沒有 bool 這個關鍵字,所以各家 compiler 自行 typedef 或是 define 了 BOOL 這個型別 (或是 marco),通常它真正的型別是 int。例如微軟的 Windows API,而現代的 C++ (C99之後) 雖然加入了 bool 這個內建型別,但為了向下相容,Windows API 還是以 BOOL 來表示 Boolean 值。無論如何,現在應該儘量少用 BOOL 這個過時又不安全的東西了( 因為 BOOL 的值可能不為 TRUE 也不為 FALSE)。
言歸正傳,bool 的 domain 應該只有 true 跟 false,這是廢話,但也因為這樣,我們無法用 bool 表示一個不確定的狀態。例如我們設一個 function 叫作 IsPrinterExists( ),用來偵測目前有沒有印表機存在,原型如下:
bool IsPrinterExists();
我們預期 IsPrinterExists( ) 應該回傳 true 表示有印表機,false 表示沒有,但如果偵測過程中有錯誤,那不管它回傳 true 或 false 都是不正確的(雖然設計上我們通常會當作 false 來處理,實務上大多也正確),應該要是一個 unknown 的值。
Boost 引入一個新的型別,名為 tribool,它與 bool 差不多,但除了 true 跟 false 外還多了一個狀態 indeterminate。tribool 的 compare operation 有下列規則:
- indeterminate 不是 true 也不是 false。
- 任何與 indeterminate 比較的結果都是 indeterminate。
- 對 || operator,只有與 true 的運算結果為 true,其它則為 indeterminate。
- 對 && operator,只有與 false 的運算結果為 false,其它則為 indeterminate。
- indeterminate 的 ! 運算結果還是 indeterminate。
- 可以使用 indeterminate( ) 來判斷是否為 indeterminate。
#include<boost/logic/tribool.hpp>
using namespace boost;
tribool tb(true); // true
tribool tb2(!tb) // false
if(tb)
{
// go here
tb2 = indeterminate; // tb2 is indeterminate
// OK, compare with indeterminate
if( tb2 == indeterminate)
{
// go here
cout << tb2 || true; // true
cout << tb2 && false; // false
}
if(tb2)
cout << "never printed"; // tb2 is not ture
if(!tb2)
cout << "never printed"; // tb2 is not false
if( indeterminate(tb2) )
cout << "indeterminate"; // yes
}
std::map<int, std::string> myMap; ... ... std::map<int, std::string>::iterator itor = myMap.begin(); // do something with itor
// Variable i is explicitly declared auto (local variable). auto int i = 0; // Variable j is implicitly declared auto (local variable). int j = 0;
在 VC2010 及 C++0x 中,auto 有了新的作用,用來表示一個經由 compiler 推導的型別 (Deduce Variable Type)。你可以在變數宣告前加上 auto 並給予初始值,該變數的型別會根據初始值來決定。可以被推導的型別有:const、volatile、pointer、reference 及 rvalue reference。
我們可以在compile時加上參數。以選擇我們對於 auto 的使用方式:
- /Zc:auto- : 表示將auto當成舊式的 storage-class specifiers
- /Zc:auto (default): 表示將auto當成新式的 deduce variable type
// 宣告
// Variable j is explicitly type int.
int j = 0;
// Variable k is implicitly type int because 0 is an integer.
auto k = 0;
// 宣告 iterator (由其在loop裡)
deque<double> dq1(2,0.1);
for (auto it = dq1.begin(); it != dq1.end(); ++it)
{
// do something
}
for_each(auto elem in dq1)
{
// do something
}
// 宣告 pointer
double x = 12.34;
auto *y = new auto(x), **z = new auto(&x);
// More
auto x = 1, *y = &x, **z = &y; // Resolves to int.
auto a(2.01), *b (&a); // Resolves to double.
auto c = 'a', *d(&c); // Resolves to char.
auto m = 1, &n = m; // Resolves to int.
// 搭配 :? 使用
int v1 = 100, v2 = 200;
auto x = v1 > v2 ? v1 : v2;
// 搭配 const 使用
int f(int x) { return x; }
int main()
{
auto x = f(0);
const auto & y = f(1);
int (*p)(int x);
p = f;
auto fp = p;
...
} auto 雖然好用,但它並非萬能,以下為一些誤用 auto 的情況 (以下皆使用新式 auto,即 Compile with /Zc:auto )
- 不能跟其它的 type-specifier 一起使用
// error auto int x;
- 用 auto 宣告變數必需給初始值
// error auto x1; auto y1, y2, y3; auto z1 = 1, z2, z3 = -1;
- auto 不可當作函式回傳型別, 亦不可當作 array 型別
// error
auto f( ){ }
auto a[5];
auto b[1][2];
auto y[5] = x;
auto z[] = {1, 2, 3};
auto w[] = x;
- auto 不可當作參數, 或 template 參數的型別
// error
void f(auto j){}
template<class T> class C{};
int main()
{
C<auto> c; // C3539
return 0;
}
- auto 搭配 new 使用時必需有初始值
// error new auto(); auto x = new auto();
- auto 不可被推導成 void, 亦不可宣告一個 auto pointer, 卻代入一物件(或內建型別)當初始值
// error
void f(){}
auto x = f();
auto* x = 123.0;
class A { };
A x;
auto *p = x;
- 不可以該 auto 變數來自我初始化
// error auto a = a; auto b = &b; auto c = c + 1; auto* d = &d; auto& e = e;
- 不可將其它型別轉型(cast)成 auto 型別
// error auto(value); (auto)value; auto x1 = auto(value); auto x2 = (auto)value; auto x3 = static_cast<auto>(value);
- 在同一行所宣告的 auto 變數, 都必需被推導成同一型別
// error // Variable x1 is a pointer to char, // but y1 is a double. auto * x1 = "a", y1 = 3.14; // Variable c is a char, // but c1, c2, and c3 are pointers to pointers. auto c = 'a', *c1 = &c, * c2 = &c1, * c3 = &c2; // Variable x2 is an int, // but y2 is a double and z is a char. auto x2(1), y2(0.0), z = 'a'; // Variable a is a pointer to int, // but b is a pointer to double. auto *a = new auto(1), *b = new auto(2.0);
- 不可對 auto 使用 sizeof 或 typeid
auto x = 123; sizeof(x); // OK sizeof(auto); // Error auto x = 123; typeid(x); // OK typeid(auto); // Error
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1; // type is const int&&
decltype(i) x2; // type is int
decltype(a->x) x3; // type is double
decltype((a->x)) x4; // type is const double&
#include <boost/typeof/typeof.hpp>
vector<string> func()
{
vector<string> v(10);
return v;
}
int main()
{
BOOST_TYPEOF(2.0*3) x = 2.0*3;
BOOST_AUTO(y, 2.3) ;
BOOST_AUTO(&a, new double[20]);
BOOST_AUTO(p, make_pair(1, "string"));
BOOST_AUTO(v, func() );
return 0;
}
std::auto_ptr<int> ptr1 ( new int (2) ); std::auto_ptr<int> ptr2; ptr2 = ptr1 ; // transfer ownership from ptr1 to ptr2
Path: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer2. 重開機 (或重開explorer)
Key: ShowDriveLettersFirst
Value: 4