C++11中用{}初始化,有等於號和沒等於號的區別是什麼?
之前一直以為兩者是等價的,但今天用tuple的時候發現,在G++5.1.0下
tuple&
s = {1, "1234"};
tuple&s{1, "1234"};
前者編譯報錯,報錯信息是
error: converting to "std::tuple&
, std::allocator& &> &>" from initializer list would use explicit constructor "constexpr std::tuple&<_T1, _T2&>::tuple(_U1, _U2) [with _U1 = int; _U2 = const char ()[5]; & = void; _T1 = int; _T2 = std::__cxx11::basic_string& ]" 後者可以順利編譯
根據報錯信息,編譯器好像是想把initializer list轉換成tuple,但由於tuple的構造函數是explicit的,所以編譯失敗
為什麼它會把{}看作initializer list呢?initializer list不應該是相同類型的嗎?{1, "1234"}顯然是不同類型的呀?而且我去查了下tuple頭文件,裡面並沒有以initializer list為參數的構造函數呀?如果把有等於號的看作隱式轉換的話,那當{}為構造函數的時候又該怎麼理解呢?比如
using namespace std;
struct node {
int a, b;
node(int a, int b) : a(a), b(b) {}
};
int main() {
node s = {1, 2};
}
這兩種寫法到底有什麼區別呢?
第一種叫copy-initialization, 第二種叫braced-initialization,若你要完整的知道失敗的原因,你需要知道標準對這兩者的差別:Effective Modern C++ Note 01,可以參考我這個文章裡面提到當構造函數是explicit的時候,copy-initialization失敗的原因。
前者是構造struct的語法糖,後者才是「通用初始化」,可以適用各種場合。
那就用
auto s = make_tuple(1, string("1234"));
有等於號的叫做隱式轉換構造,而tuple(C++14還是17之前)是不允許隱式轉換構造的
至於你說的initializer list,不要和std::initializer_list&
在我看來,題主的例子正是這兩者唯一的區別,即帶等號的copy-list-initialization不允許調用explicit構造函數。此規定見 [over.match.list] :
In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.
由此延伸出的引用的列表初始化也是一樣:
struct A {
explicit A(int);
};
const A a1 = {0}; // error
const A a2{0}; // ok
歡迎指出其他具體的不同之處。
順便,C++17後std::tuple的構造函數不再總是explicit,用copy-list-initialization也可以了。
C++17已經fix了吧,不會默認把這個當做 initializer_list
std::tuple::tuple - cppreference.com
Conditionally-explicit constructors in C++17 make it possible to construct a tuple in copy-initialization context using list-initialization syntax
g++ Chapter 1. Status:
Improving pair and tuple N4387 6.1
N4387: Improving Pair and Tuple (Revision 3)
https://godbolt.org/g/LKcuui
推薦閱讀:
※聲明多個指針時,為什麼實際只有第一個是指針?
※cpp 如何 debug memory leak?
※C++中類的構造函數,成員變數是在初始化列表初始化還是在函數體中進行賦值?
※cout << sizeof(vector<int>);輸出是32,為什麼?
※如何用 VS 2013 打包 VC++ 程序?
TAG:C |