2017-10-05 71 views
1

跑進模板扣除導遊另一怪事後C++17 template deduction guide not used for empty parameter set?(即錯誤https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81486仍然沒有固定在樹幹GCC不幸的是:():C++ 17模板演繹指南不適用於空參數集(版本2)?

#include <utility> 

template <class T> struct success 
{ 
    T value; 
    constexpr success(T &&v) 
     : value(std::move(v)) 
    { 
    } 
    constexpr success(const T &v) 
     : value(v) 
    { 
    } 
}; 
template <> struct success<void> 
{ 
}; 
template <class T> success(T /*unused*/)->success<T>; 
success()->success<void>; 

template<class T> struct foo 
{ 
    foo(success<void>) {} 
}; 

int main(void) 
{ 
    auto a = success{5};  // works 
    auto b = success{};   // works 
    auto c = success{"hello"}; // works 
    auto d = success(5);  // works 
    //auto e = success();   // FAILS on GCC 7.2! 
    auto f = success("hello"); // works 
    foo<void> g(success());  // FAILS 
    static_assert(std::is_same<decltype(a), success<int>>::value, ""); 
    static_assert(std::is_same<decltype(b), success<void>>::value, ""); 
    static_assert(std::is_same<decltype(c), success<const char *>>::value, ""); 
    static_assert(std::is_same<decltype(d), success<int>>::value, ""); 
    //static_assert(std::is_same<decltype(e), success<void>>::value, ""); 
    static_assert(std::is_same<decltype(f), success<const char *>>::value, ""); 
    return 0; 
} 

令人驚訝的線,至少對我來說,是foo<void> g(success());無法使用兩個鐺6.0幹線和GCC 7樹幹模板扣除指南,你可以在https://godbolt.org/g/7m1Zhk

看到我覺得這令人驚訝,而不是人們所期望的是什麼。模板嚮導說,安縵success()應被理解爲success<void>。這應該foo的unambi工作得很好guous構造函數接受success<void>。相反鐺6.0主幹報道:

34 : <source>:34:17: error: use of class template 'success' requires template arguments; argument deduction not allowed in function return type 
    foo<void> g(success());  // FAILS 
       ^~~~~~~ 
3 : <source>:3:27: note: template is declared here 
template <class T> struct success 
         ^

和GCC 7.3主幹報道:

<source>: In function 'int main()': 
34 : <source>:34:25: error: 'auto' parameter not permitted in this context 
    foo<void> g(success());  // FAILS 
         ^

任何人能解釋這到底是怎麼回事呢?這是C++ 17標準中的缺陷嗎?

回答

4

我相信你已經遇到了最令人痛苦的解析的新形式。

請記住,在任何超出名稱查找的語義規則對其應用之前,都會確定任何代碼的語法形式。現在,一個模板名稱在語法上是有效的簡單類型說明符,可以解析

foo<void> g(success()); 

無論是作爲一個對象g與初始的定義或功能g的聲明。根據最煩人的分析規則,函數解析「勝利」,因此g聲明函數返回foo<void>,其中一個未命名參數是一個不帶參數的函數,返回佔位符類模板類型success

但是,當語義檢查確實啓動時,這不是類模板佔位符類型的有效用法之一,因此該程序是格式不正確的。

注意鐺會成功,如果我們做一些調整,以避免最棘手的解析:

foo<void> g2{success()}; 
struct bar { bar(int, succeed<void>) {} }; 
bar g3(1, success()); 

不過,我認爲以下雙括號招也應該工作,但它只是導致從鐺新的錯誤消息。我不知道這個是怎麼回事:

foo<void> g4((success())); 
+0

那個叮鐺聲的信息其實是[bug 34091](http://llvm.org/pr34091)。 – Rakete1111

+0

好的,謝謝你對原因的確認。很難在這個和其他答案之間做出選擇,兩者都很好,但這個也有一個解決方法,所以我認爲它更好。 –

2

這是最令人頭疼的解析。

foo<void> g(success());  // FAILS 

是一個函數,名爲g,返回一個foo<void>的聲明,並採取作爲一個[無名]類型的指針,以無參函數參數返回success

但是,success不是一種類型,它是一個模板名稱,並且不能使用模板名稱作爲函數的返回類型,而只能使用完整類型。因此,錯誤。

+0

template-name,not template-id。 –

+0

@ T.C。乾杯,模板id是你真正想要的不是它...... – Barry

+0

「但是,成功不是一種類型,它是一個模板名稱,並且你不能使用模板名稱作爲函數的返回類型,只有一個完整的類型,因此,錯誤。「 我現在看到問題了。未來標準的一個解決方法是如果模板類型默認其所有模板參數,那麼該缺省可以被注入類型空間以及模板空間。是的,我同意這是一個糟糕的角落案例,但令人煩惱的解析問題使我無法用更簡潔的模板推導指南系統替換一組免費的功能和填充類型。哪個是傷心:( –

相關問題