2015-11-30 100 views
2

考慮下面的代碼片段...initializer_list <T>不能轉換爲initializer_list <U>,而T3可轉換至U

void boo(std::initializer_list<unsigned> l) 
{ 
} 

template <class T> 
void foo(std::initializer_list<T> l) 
{ 
    //Even though T is convertable, initializer list is not...:-(
    boo(move(l)); 
} 

int main() 
{ 
    foo({1u,2u,3u}); //Compiles fine as expected 
    foo({1,2,3}); //Fails to compile at line 9... - could not convert... 
    return 0; 
} 

...我很驚訝,initializer_list<int>是無法轉換爲initializer_list<unsigned>,雖然事件int轉換爲無符號。

我一直想知道用什麼方法可以寫出foo來允許轉換。能以某種方式解開具有錯誤類型的列表並重新創建具有正確類型的新列表嗎?

回答

2

儘管在編譯期間無法解壓縮初始化程序列表(以執行必要的轉換),但您可以按照您希望的方式創建它。考慮下面的代碼:

#include <initializer_list> 
void boo(std::initializer_list<unsigned> l); 

template <class... T> 
void foo(T... l) 
{ 
    boo({static_cast<unsigned int>(l)...}); 
} 

int main() 
{ 
    foo(1,2,3); 
    return 0; 
} 
2

即使T可轉換爲U,但類別Foo<T>不可轉換爲Foo<U>。對於編譯器,模板實例化中的不同類型會產生不相關類型的實例。

所以你的情況,foo({1,2,3})推導Tint,所以foo參數的類型爲initializer_list<int>。然後您嘗試將其傳遞給boo,這需要initializer_list<unsigned>,這是無關initializer_list<int>,因此編譯錯誤。

你或許可以通過避免模板專業化這個頭痛代替,即專門的foounsigned類型:

template<> 
void foo<unsigned>(std::initializer_list<unsigned>) 
{ 
    // specialization here 
} 
+1

@WernerErasmus不知道我明白你正在談論的'std :: shared_ptr'轉換... – vsoftco

+0

我的歉意。我錯了 - 我與正常派生的基礎轉換混淆。 –

+1

@WernerErasmus哦,是的,這是一個不同的故事,在這種情況下'T'仍然被推斷爲'Base *',但是在內部''shared_ptr'可以使用'Base *'來訪問'Derived'的虛擬接口。 – vsoftco

2

總之,這種轉換無法做到的。一旦你有一個std::initializer_list<int>對象,就沒有辦法用它來合成一個std::initializer_list<unsigned>。您可以遍歷它,但問題是關於大小的信息不是靜態可用的,因此無法從一個std::initializer_list對象生成用於構造不同的std::initializer_list對象的支撐包含的初始化程序列表。

如果boo需要接收std::initializer_list<unsigned>,那麼foo應該有一個std::initializer_list<unsigned>類型的參數。您可以將{1, 2, 3}轉換爲std::initializer_list<unsigned>。但一旦你推斷它爲std::initializer_list<int>這種可能性消失。

3

沒有。構造一個初始化器列表需要一個編譯時間已知的長度,並且使用一個初始化器列表,因爲它沒有編譯時間已知的長度。

初始值設定項列表適用於「面向用戶」的操作,其中用戶是界面的使用者。在內部使用它們不能很好地工作。

你可以使用的方法是編寫一個array_view<T>類型,它包含一系列連續內存(初始化程序列表,矢量,std數組或C數組都是範例視圖) (開始,結束,數據,大小,空,前,後方法,迭代器都是指針)。

然後給它隱式轉換從vector<T>&,vector<std::remove_const_t<T>> const&,initializer_list<std::remove_const_t<T>>等等。

void boo(array_view<const unsigned> l) 
{ 
} 

template <class T> 
void foo(std::initializer_list<T> l) 
{ 
    boo(std::vector<unsigned>{l.begin(), l.end()}); 
} 

進入一個重新分配基於斷unsigned值的一個新的緩衝區無論是l並將它傳遞給booboo消耗array_view<unsigned const>,其可以從vectorinitializer_listunsigned轉換。

然後,我們可以寫maybe_convert_list

template <class T, class U, class...LowPrecidence> 
std::vector<T> maybe_convert_list(std::initializer_list<U> l, LowPrecidence&&...) 
{ 
    return {l.begin(), l.end()}; 
} 
template <class T> 
std::initializer_list<T> maybe_convert_list(std::initializer_list<T> l) 
{ 
    return l; 
} 

template <class T> 
void foo(std::initializer_list<T> l) 
{ 
    boo(maybe_convert_list<unsigned>(l)); 
} 

或諸如此類。它僅剩下initializer_list<unsigned>。對於其他類型的列表,它會將其轉換爲std::vector<unsigned>

相關問題