2017-10-20 49 views
15

考慮下面的代碼:g ++不採用的變量推導指南,由clang拍攝++ - 誰是正確的?

template <typename... Types> 
struct list 
{ 
    template <typename... Args> 
    list(Args...) 
    { 
     static_assert(sizeof...(Types) > 0); 
    } 
}; 

template <typename... Args> 
list(Args...) -> list<Args...>; 

int main() 
{ 
    list l{0, 0.1, 'a'}; 
} 

我希望decltype(l)list<int, double, char>。不幸的是,g ++ 7.2g ++中繼未通過靜態斷言。 鏗鏘++ 5.0.0鏗鏘++幹線按預期進行編譯和工作。

godbolt.org conformance view

這是一個克++錯誤?或者有沒有理由不應該在這裏遵循扣除指南


添加在構造一個SFINAE約束似乎提供所需的行爲:

template <typename... Args, 
      typename = std::enable_if_t<sizeof...(Args) == sizeof...(Types)>> 
list(Args...) 
{ 
    static_assert(sizeof...(Types) > 0); 
} 

godbolt.org conformance view

+0

我認爲你的代碼可能不合格......對於sizeof ...(Types)== 0',你的模板構造函數沒有可行的實例... –

+0

我很努力地把它看成任何東西除了海灣合作委員會的錯誤。使用make_list()函數的先前方法可以正常工作。 https://godbolt.org/g/vag3rD –

+0

@RichardHodges很自然地用你的方法g ++不會嘗試實例化'list <>'。 –

回答

10

這是gcc bug 80871。問題是,我們結束了這組候選人的扣除:

template <class... Types, class... Args> 
list<Types...> __f(Args...); // constructor 

template <class... Args> 
list<Args...> __f(Args...); // deduction-guide 

都是有效的(Types...可以推斷出在第一種情況下爲空),但這裏的調用應該是不明確的 - 無論是不是更加專業化另一個。 Types...不參與此處排序(類似於[temp.deduct.partial]/12中的示例)。所以正確的行爲是進入下一個tiebreaker,其中favors deduction-guides。因此,這應該是list<int, double, char>

但是,海灣合作委員會的行爲是贊成的構造函數,因此static_assert觸發器,因爲Types...確實是空的在這種情況下。