0%

Misc C++11 Feature

儲存了一堆文件,消化一下。

Default template arguments for function templates

以下這個程式碼,在C++98是不可行,但是C++11可以的。

1
2
3
4
5
6
7
template <typename T = int> void Foo(T t = T())
{
}
Foo(12L); // Foo<long>
Foo(10.1); // Foo<double>
Foo('A'); // Foo<char>
Foo(); // Foo<int>

根據Stackoverflow的說法,可以寫類似這樣的Code>

1
2
3
template <typename Iterator, typename Comp = std::less<Iterator>>
void sort(Iterator beg, Iterator end, Comp c = Comp()) {
}

不過當Function Template在Argument deduction時,可能會有以下的問題。

1
2
3
4
5
6
template <typename B, typename T = int>
void Bar(B b = B(), T t = T()) {}
Bar(10); // Bar<int, int>
Bar(10L); // Bar<long, int>
Bar(10L, 20L); // Bar<long, long>
Bar(); // Compile error, couldn't deduce template parameter ‘B’

同樣的在Function Template overload的時候,也是地雷區。

1
2
3
4
5
template <typename T = int> void Foo(T t = T()) {}
template <typename B, typename T = int> void Foo(B b = B(), T t = T()) {}
Foo(12L); // Compile error, ‘Foo(long int)’ is ambiguous
// void Foo(T) [with T = long int] and void Foo(B, T) [with B = long int; T = int]
Foo(); // Compile OK, choose the first function

C++真是細節有夠多的程式語言。

Explicit conversion operators

在C++98的時候,explicit能做的就只有這樣。

1
2
3
4
5
6
class Test1 {
public:
explicit Test1(int) {}
};
Test1 t1(10);
Test1 t2 = 20; // compile error

而對這樣的處理無能為力。

1
2
3
4
5
6
7
8
9
10
11
12
class Test1 {
public:
explicit Test1(int) {}
};
class Test2 {
int x;
public:
Test2(int i) : x(i) {}
operator Test1() { return Test1(x); }
};
Test2 t1 = 10;
Test1 t2 = t1;

t2被偷偷轉換成Test1類型而無法輕易發現,在C++11之後,增加了這樣的能力。

1
2
3
4
5
6
7
8
9
class Test2 {
int x;
public:
Test2(int i) : x(i) {}
explicit operator Test1() { return Test1(x); }
};
Test2 t1 = 10;
Test1 t2 = (Test1)t1;
Test1 t3 = t1; // Compile error

不過bool算是例外。

1
2
3
4
5
6
7
8
9
10
11
12
class Test3 {
public:
explicit operator bool() { return true; }
};
void Foo()
{
Test3 t3;
if (t3) {
// if constructor's bool conversion is treated as explicit.
}
bool b = t3; // Compile error
}

Initializer lists and Uniform initialization syntax

在C語言可以這樣寫沒問題

1
int a[] = {1, 2, 3};

不過在C++98,用std::vector的時候,就只能寫成這樣。

1
2
3
4
std::vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);

支援Initializer lists之後,終於可以寫出比較美觀的程式碼

1
std::vector<int> a = {1, 2, 3};

你也在自己的城市中使用Initializer lists,如下:

1
2
3
4
5
6
7
template <typename T>
void print(const initializer_list<T>& nums)
{
for (auto num : nums)
cout << num << endl;
}
print({1, 2, 3, 4});

既然有了Initializer lists之後,C++11更進一步將Initialization簡化,使用同樣的語法來做初始化。
Case 1:

1
2
3
4
5
6
7
struct C
{
int a;
int b;
C(int i, int j) {}
};
C c {0,0}; //C++11 only. Equivalent to: C c(0,0);

Case 2

1
int* a = new int[3] { 1, 2, 0 }; //C++11 only 

Case 3

1
2
3
4
struct X {
int a[4];
X() : a{1,2,3,4} {} //C++11, member array initializer
};

Case 4:

1
2
3
4
struct C
{
int a = 7; //C++11 only
};

更進一步,將Initializer list和 Uniform initialization雙見合併。

1
2
map<string, string> singers ={ {"Lady Gaga", "+1 (212) 555-7890"},
{"Beyonce Knowles", "+1 (212) 555-0987"}};

這樣的程式碼易讀許多。