對于以下代碼,為什么編譯器將我的函式呼叫與(意外的)模板函式匹配:
首先這里是可用的功能模板:
// First function template
template <typename T, typename U>
auto sub(T x, U y) {
return x - y;
}
// Second function template
template <typename T>
auto sub(T x, T y) {
return x - y;
}
現在假設我從一個模板引數推導陳述句開始:
sub(5.2, 2.1);
上面的陳述句應該反過來使用上面提供的第二個函式模板實體化一個函式實體(模板函式) ,最終看起來像這樣:
template<>
double sub<double>(double x, double y) {
return x - y;
}
下一條陳述句不會實體化新的模板函式,因為它可以與之前創建的函式匹配。
sub<double>(2.3, 234.2);
現在下面的陳述是我有點困惑的地方。
sub<double>(2.3, 234.0f); // Weird one
盡管我提供了一個實際型別(double),但在模板引數中,我遇到了一個奇怪的結果。我故意將第二個函式引數設為浮點數,以便與我們之前提到的函式實體(模板函式)不完全匹配,并且預期會發生浮點提升并將浮點數提升為雙精度然后匹配模板函式,這不是最終發生的事情......而是它使用頂部提供的第一個函式模板創建了一個新的函式實體(模板函式) ,最終看起來像這樣:
template<>
double sub<double, float>(double x, float y) {
return x - y;
}
我感到困惑的是,我如何認為編譯器更喜歡促銷而不是這樣的東西,或者我可能把它與其他東西混淆了,我希望有人可以澄清一下。
一個也困擾我的問題是,我不知道如何才能顯式呼叫我真正想要的模板函式,例如:
sub<double>(2, 2);
如果我希望它呼叫具有兩種引數型別的模板函式,double并且只是希望我的兩個引數都從數字轉換int為double. 按照這個邏輯,我不能這樣做,因為編譯器最終會創建一個看起來像這樣的新函式實體(模板函式):
template<>
double sub<double, int>(double x, int y) {
return x - y;
}
我必須提到我不是在談論如何轉換我的論點,因為我很清楚我可以使用static_cast它們,我也不是在談論做這樣的事情:
sub<double, double>(2, 2);
當然,使用第一個函式模板來創建一個新的函式實體(模板函式),而不是使用已經可用的模板函式(它是通過使用第二個函式模板創建的)。如果真的有辦法,有人可以解釋我怎么能做到嗎?所有這一切,主要是因為我試圖真正理解概念。
uj5u.com熱心網友回復:
您可以提供模板引數的部分串列。例如,如果您有
template <typename A, typename B, typename C>
void foo(A, B, C);
然后這些電話
foo(1,2,3);
foo<int>(1,2,3);
foo<int, double>(1,2,3);
foo<int, double, float>(1,2,3);
都很好。
所以sub<double>(2.3, 234.2f);仍然匹配第一個函式模板和第二個模板的實體化,前者是更好的匹配,因為它不需要轉換。只有當兩個匹配都同樣好時,多載決議才更喜歡非模板而不是模板1。如果模板更匹配,則使用它。
當兩個引數的型別不同時,可以強制選擇第二個模板:
auto x = (static_cast<float(*)(float, float)>(sub))(1, 2.0);
但這當然違背了目的。為了方便使用,你需要引入一些其他的選擇機制,例如
enum class same { type };
template <typename T, same = same::type>
auto sub(T x, T y)...
... sub<double, same::type>(2.3, 234.0f) ...
1或者更確切地說,需要推導模板引數的呼叫與不需要推導任何內容的呼叫。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/419344.html
標籤:
上一篇:C 使用cout列印結構
