2016-12-07 111 views
15

考慮粘貼在下面的代碼。我已經定義了一個非常簡單的類,爲此編譯器生成一個隱式演繹指南,因此它可以在沒有顯式模板參數的情況下構建。但是,模板參數推導工作從只直接轉發到目標類的簡單的別名模板構造一個對象:類別模板參數扣除不與別名模板一起使用

template< typename A, typename B > 
struct Foo { 
    Foo(A const &a, B const &b) 
      : a_(a), b_(b) 
    { } 

    A a_; 
    B b_; 
}; 

template< typename A, typename B > 
using Bar = Foo<A, B>; 

auto foobar() { 
    Foo r{1, 2}; 
    Bar s{3, 4}; 
    // ../src/geo/vector_test_unit.cpp: In function 'auto foobar()': 
    // ../src/geo/vector_test_unit.cpp:16:6: error: missing template arguments before 's' 
    // Bar s{3, 4}; 
    //  ^
    return 1; 
} 

正如你可以從上面的代碼註釋看,G ++是給我有關使用沒有模板參數的別名模板的錯誤。我希望在這種情況下,模板論證扣除將被轉發。

那麼,我的問題:這是通過明確設計類模板參數演繹提案的當前措詞嗎?或者,這是該功能的當前g ++實現中未完成的功能或缺陷?這對於提案的作者或者C++ ISO委員會來說可能是一個更大的問題,但是如果他們中的任何一個人看到這樣的話:這個特性的最後措辭是否包括啓用別名模板也是理想的爲他們生成隱式指南?

我可以理解,由於別名模板可以具有任何類型的模板參數,因此編譯器可能無法總是成功推導出目標類模板參數,但在這種情況下,我希望編譯器會是能夠以同樣的方式直接爲目標課程。

我在前幾天使用gcc構建gcc,使用--std=c++1z。完整版本信息是:gcc version 7.0.0 20161201 (experimental) (Homebrew gcc HEAD- --with-jit)

回答

21

這是我們在制定提案時考慮的一項功能,但最終因爲我們還沒有足夠好的設計而被削減。特別是,關於如何選擇和將別名模板中的演繹指南轉換爲別名模板的演繹指南,有一些細微之處。如果別名模板不是另一個模板的簡單別名,那麼對於如何表現還存在一些疑問。一些例子:

template<typename T> struct Q { Q(T); };  // #1 
template<typename T> struct Q<T*> { Q(T); }; // #2 
template<typename T> using QP = Q<T*>; 
int *x; 
Q p = x; // deduces Q<int*> using #1, ill-formed 
QP q = x; // deduces Q<int*> using #1, or 
      // deduces Q<int**> using #2? 

template<typename T> Q(T) -> Q<T>; // #3 
QP r = x; // can we use deduction guide #3 here? 

template<typename T> Q(T*) -> Q<T**>; // #4 
int **y; 
QP s = y; // can we use deduction guide #4 here? 

template<typename T> struct A { typedef T type; struct Y {}; }; 
template<typename T> using X = typename A<T>::type; 
template<typename T> using Y = typename A<T>::Y; 
X x = 4;   // can this deduce T == int? 
X y = A<int>::Y(); // can this deduce T == int? 

有像樣的回答了上述問題,但解決這些問題增加了複雜性,似乎最好禁止用於C++ 17別名模板扣除,而不是急於東西瑕疵英寸

我預測我們將看到一篇來自費薩爾的文章,提出了C++ 20的這個特性。

+0

我一次建立並編譯您的示例文件,試圖逐步瞭解它。我只用#1,#2和行int * x編譯了它; Q p = x;'。正如你所指出的,它會給出一個錯誤,除非我刪除#2並重新編譯。來自g ++的錯誤信息是'[...]錯誤:從'int *'到'int'的無效轉換... Q p = x; ...注意:初始化'Q :: Q(T)[with T = int]'參數1'template struct Q {Q(T); };'。對我來說,就像你說的那樣,它試圖使用#2而不是#1。我不瞭解什麼? –

+1

@squidbidness對於類模板參數推導,'Q p = x;'這一行使用#1推導'p'的類型爲'Q '。選擇該類型後,它推斷'Q '應該使用'Q '部分專業化,推導出'T = int'。最後,它試圖調用一個'Q '構造函數,其參數類型爲'int *',因爲唯一的構造函數(默認/複製/移動ctors除外)需要一個int類型,所以它不起作用。 –

+0

謝謝你的澄清。讓我感到困惑的部分是我的心智模型已經推導出'p'的類型,並且選擇一個模板專業化作爲一個相同的過程。指出他們是單獨的步驟幫助我更好地推理它。 –