2017-01-10 149 views
3

我的問題是關於std::initializer_list類型之間缺少轉換,其中包含的類型或多或少具有cv限定的轉換似乎很容易實現。std :: initializer_list <int const>不能從std :: initializer_list構建<int>

考慮下面的代碼是無效的:

std::initializer_list<int> x{1,2,3,4,5,6}; 
std::initializer_list<int const> y = x; // error! cannot convert! 

現在考慮std::optional而忽略了可笑的類型:

std::optional<std::vector<int>> x{std::in_place, {1,2,3,4,5}}; // OK 
std::optional<std::vector<int const>> y{std::in_place, {1,2,3,4,5}}; // error! 

承擔語言規範要求推導非CV合格U的對於std::initializer_list<U>默認情況下。

據我所知,具有std::initializer_list構造函數重載std::optional(和std::anystd::variant)整點是避免指定初始化列表的確切類型。要獲得上面代碼的第二行來編譯,那正是你必須做的。

std::initializer_list已經擁有一個const*它的數據(無論如何在libc++)。我沒有理由看到上面的代碼不工作?這是一個可以解決的問題,或者我錯過了什麼?

+3

這是一種很難「忽略可笑的類型」,當'矢量'在C++中明確*不合法*。那麼爲什麼你會期望'initializer_list '工作?你會用它初始化什麼? –

+0

說實話,我不知道。當我發現這一點時,我正在編寫一個通用的包裝類型。 – xcvr

+0

也許這對於一些類似於「dynarray」的類型是有意義的。 – xcvr

回答

3

聽起來像你的問題是爲什麼std::initializer_list<T const>不能從std::initializer_list<T>構造,儘管事實上它很容易實現這樣的轉換。

我認爲答案是,你不應該有std::initializer_list<T const>首先,因爲,正如你所指出的,std::initializer_list<T>只能給const訪問它的元素無論如何。

因此可以說C++中存在一個「文化規範」,你不應該有任何需要std::initializer_list<T const>參數的構造函數。例如,沒有一個標準庫容器可以做,因爲無論如何cv限定的值類型都是非法的(除非是std::array,當然,它無論如何都沒有用戶定義的構造函數)。

如果你寫你自己的類型MyContainer支持MyContainer<T const>,那麼我建議你使它看起來像下面這樣:

template <class T> 
class MyContainer { 
    public: 
    MyContainer(std::initializer_list<std::remove_cv_t<T>> il); 
    // ... 
}; 
+0

「文化規範」似乎是正確的!如果某人(你?)可以解釋爲什麼如果所有初始化器列表與「std :: initializer_list 」具有相同的語義,那麼爲什麼我不會推斷這是爲了'std :: initializer_list '。 – xcvr

+1

@xcvr,因爲'std :: initializer_list'的模板參數是使用模板參數推導的通常規則推導出來的,它不會推導出cv限定類型,引用類型,數組類型或函數類型。 – Brian

+0

雖然我認爲通常的模板參數推導規則在窗口不能被推斷出來的時候,除非它被指定爲'std :: initializer_list '。 – xcvr

相關問題