2017-06-13 80 views
4

我一直在尋找這個問題在這裏找到Template function overload for type containing a type函數模板重載及編譯器優化

凡OP user2079802爲他/她的問題提供了這個代碼:

我嘗試做以下:

#include <iostream> 
#include <vector> 
#include <tuple> 

template <typename T> 
void f(T t) { 
    std::cout << "1" << std::endl; 
} 

template <typename T, typename V> 
void f(T<std::tuple<V>> t) { 
    std::cout << "2" << std::endl; 
} 

int main() { 
    f(std::list<double>{}); // should use first template 
    f(std::vector<std::tuple<int>>{}); // should use second template 
} 

在C++ 14中這樣做的最簡單方法是什麼?我認爲我可以通過這種方式進行模式匹配,但編譯器不會擁有它。

而且songyuanyao提供這樣的回答:

參數T作爲模板的名稱,所以它應該被聲明爲template template parameter模板。例如

template <template <typename...> class T, typename V> 
//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
void f(T<std::tuple<V>> t) { 
    std::cout << "2" << std::endl; 
} 

LIVE


這是沒有提供實際上修正編譯錯誤以及代碼沒有正常運行的答案。爲了清楚起見,我正在詢問關於此代碼段的問題。 OP最初嘗試對模板類型進行模式匹配,但對模板模板參數的語法不正確。當我通過我的IDE跑了答案,編譯器&調試器{MSVS 2017年CE}在64位英特爾Windows 7計算機上運行我碰巧注意到它們的主要功能是,在OP的函數調用:

f(std::list<double>{}); 
f(std::vector<std::tuple<int>>{}); 

第二個函數調用實際上是調用第一個函數模板而不是第二個。這確實引起了幾個問題:

  • 這是由於編譯器優化?
  • 這是重載解析的結果嗎?
  • 在編譯器的底層實際發生了什麼,它在 選擇使用第二個函數模板?
  • 或者這是MSVC編譯器的錯誤嗎?
+0

呃,你會得到輸出「1 2」嗎?或者您是否從調試器中看到的結論得出了「第二個函數調用實際上調用第一個函數模板」的結論? –

+0

@DanielJour我打印的值是'1'而不是'2',因此它調用第一個函數而不是第二個函數。 –

+2

這是MSVC編譯器中的一個錯誤。 –

回答

2

它實際上不是MSVC編譯器中的錯誤。這實際上是標準中有關默認模板參數的模糊性的結果。

你看,std::vector實際上有2個模板參數:類型和分配器。

如果從重構問題的答案佔分配器

template <typename T> 
void f(T t) { 
    std::cout << "1" << std::endl; 
} 

template <template <typename...> class T, typename V> 
void f(T<std::tuple<V>, std::allocator<std::tuple<V>>> t) { 
    std::cout << "2" << std::endl; 
} 

它會在所有的編譯器正常工作:msvc demogcc democlang demo

Here's the original defect report(CWG 150)

P0522R0有最新的討論,2016年11月,他們提出,匹配您在songyuanyao的回答中引用的那種部分模板將根據標準是正確的。

P0522R0中提出的更改正在納入C++ 17標準(我選中的是N4296草案)。在標準最終確定之前,MSVC聲稱擁有完整的C++ 17支持,我不會稱之爲編譯器中的錯誤。現在,他們承認,這個具體的提案還沒有被納入到他們的編譯器中,因爲VS 2017.3 [P2](source

+0

這看起來像一個稍微不同的問題。報告中的例子被三個主要的編譯器拒絕,而OP的代碼按照g ++和clang ++的預期工作。您提出的解決方案忽略了這一點。使用參數包的方式是我們不想知道或關心可能存在的其他模板參數。你的解決方案迫使程序員知道'T'接受兩個參數,第二個參數是'std :: allocator <...>'(我們可以寫'template Tclass T',即使在C++ 03中也是如此)。幸運的是,[修復]很容易(https://pastebin.com/FmKfgqQY)。 –

+0

@ n.m。顯式使用'std :: allocator'是爲了演示目的:-)。至於這是與報告不同的問題,我傾向於(恭敬地)不同意。在使用C++ 14選項[demo](https://wandbox.org/permlink/RTRvJJAicYDUkuND)的gcc中,OPs代碼無法按預期工作,但它可以與C++ 17選項[demo](https ://wandbox.org/permlink/x0w1SsMvr0s1pDA1) – AndyG

+0

所以在gcc 6和7之間的行爲已經改變了(我只檢查了gcc 6)。 –