[英]Why can't I initialize this std::vector with an l-value?
我遇到了一個有趣的問題,但我無法理解發生了什么:
/* I WANT 6 ELEMENTS */
int lvalue = 6;
std::vector<int*> myvector { 6 }; /* WORKS FINE */
std::vector<int*> myvector{ lvalue }; /* DOESN'T WORK */
/* Element '1': conversion from 'int' to 'const unsigned __int64 requires a narrowing conversion */
從我可以看到,我提供的單個整數參數可以解釋為使用參數size_type count
調用構造函數,也可以解釋為使用初始化列表的構造函數。 似乎只有在我提供 l 值時才調用initialiser_list
構造函數,但在我提供 r 值int
時才調用size_t count
構造函數(好吧,至少是文字)。 為什么是這樣?
這也意味着:
int num_elements = 6;
std::vector<int> myvector{num_elements};
導致只有大小為1
的向量;
std::vector<int> myvector(num_elements);
結果是一個大小為num_elements
的向量,但我認為應該避免這種初始化,因為偶爾會遇到最棘手的解析問題。
該問題並不特定/僅限於std::vector
,而是標准下面引用的規則的結果。
讓我們逐案看看發生了什么,以及為什么我們在使用lvalue
時會收到提到的縮小轉換錯誤/警告。
這里我們考慮:
int lvalue = 6; // lvalue is not a constant expression
//---------------------------v------------------->constant expression so works fine
std::vector<int*> myvector { 6 };
std::vector<int*> myvector{ lvalue };
//--------------------------^^^^^^--------------->not a constant expression so doesn't work
首先注意std::vector<int*>
沒有初始化列表構造函數,它采用int
的初始化列表。
所以在這種情況下,將使用size_t count
ctor。 現在讓我們看看縮小轉換錯誤/警告的原因。
我們在使用名為lvalue
的變量時得到錯誤/警告而在使用 prvalue int
時沒有得到錯誤/警告的原因是因為在前一種情況下lvalue
不是一個常量表達式,所以我們有一個縮小轉換。 這可以從dcl.init.list#7中看出:
縮小轉換是隱式轉換
- 從整數類型或無作用域枚舉類型到不能表示原始類型的所有值的整數類型,除非源是常量表達式,其值在整數提升后將適合目標類型。
(強調我的)
這意味着從int
類型的lvalue
(它是一個左值表達式)到向量的std::vector::vector(size_t, /*other parameters*/)
ctor 的size_t
參數的轉換是窄化轉換。 但是從純右值 int 6
到向量的std::vector::vector(size_t, /*other parameters*/)
的size_t
參數的轉換不是窄化轉換。
為了證明確實如此,讓我們看一些例子:
int main()
{
//----------------v---->no warning as constant expression
std::size_t a{1};
int i = 1;
//----------------v---->warning here i is not a constant expression
std::size_t b{i};
constexpr int j = 1;
//----------------v---->no warning here as j is a constexpr expression
std::size_t c{j};
return 0;
}
struct Custom
{
Custom(std::size_t)
{
}
};
int main()
{
//-----------v---->constant expression
Custom c{3}; //no warning/error here as there is no narrowing conversion
int i = 3; //not a constant expressoion
//-----------v---->not a constant expression and so we get warning/error
Custom d{i}; //warning here of narrowing conversion here
constexpr int j = 3; //constant expression
//-----------v------>no warning here as j is a constant expression and so there is no narrowing conversion
Custom e{j};
return 0;
}
這里我們考慮:
//------------v-------------------------->note the int here instead of int* unlike case 1
std::vector<int> myvector{num_elements};//this uses constructor initializer list ctor
在這種情況下,有一個可用於std::vector<int>
的初始化列表 ctor,它比size_t count
構造函數更可取,因為我們在這里使用了大括號{}
而不是括號()
。 因此將創建一個大小為1
的向量。 更多詳細信息,請參閱為什么在使用花括號初始值設定項列表時首選 std::initializer_list 構造函數? .
另一方面,當我們使用:
std::vector<int> myvector(num_elements); //this uses size_t ctor
這里std::vector
的size_t
ctor 將用作初始化列表 ctor 在這種情況下甚至不可行,因為我們使用了括號()
。 因此將創建一個大小為6
的向量。 您可以使用下面給出的示例來確認這一點:
struct Custom
{
Custom(std::size_t)
{
std::cout<<"size t"<<std::endl;
}
Custom(std::initializer_list<int>)
{
std::cout<<"initializer_list ctor"<<std::endl;
}
};
int main()
{
Custom c(3); //uses size_t ctor, as the initializer_list ctor is not viable
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.