假設我們有以下簡單的代碼:
#include <iostream>
#include <type_traits>
struct S {
template <typename T> explicit S(T) noexcept requires std::is_signed<T>::value {
std::cout << "T\n";
}
template<typename T> explicit S(const T&) noexcept {
std::cout << "const T&\n";
}
};
int main() {
S s(4);
}
此代碼使用 clang 編譯并列印 'T',但使用 gcc 我們有以下錯誤:
error: call of overloaded 'S(int)' is ambiguous
我的問題是哪個編譯器有錯誤、gcc 或 clang?
uj5u.com熱心網友回復:
海灣合作委員會是正確的。這是模棱兩可的。
首先,我們必須看看隱式轉換序列。在這兩種情況下,都涉及身份轉換序列:inttoint和intto const int&(由于[over.ics.ref]/1 ,后者被認為是身份轉換序列)。
其次,我們看一下關于標準轉換序列的決勝局規則,[over.ics.ref]/3.2。這些決勝局均不適用于這種情況。這意味著沒有一個隱式轉換序列比另一個更好。
我們接下來必須參加全球決勝局。即使一個多載的所有隱式轉換序列既不比另一個多載的相應隱式轉換序列好也不差,這些可以允許認為一個多載優于另一個多載。全域決勝局在[over.match.best.general]/2中定義。根據第五個要點(其他任何一個都不可能適用于這種情況),如果兩者都是模板專業化但一個模板比另一個模板更專業,則其中一個多載可能比另一個更好。
為了確定是否是這種情況,我們參考[temp.func.order],它指的是[temp.deduct.partial]。我們處于函式呼叫的背景關系中,因此根據(3.1),“使用的型別是函式呼叫具有引數的那些函式引數型別。” 然后,第 5 段去除參考,第 7 段去除頂級 cv 限定符。這樣做的結果是兩個方向的演繹都成功了。(也就是說,即使不是每個T都是 a const U&,但無論如何推演都會在這個方向上成功,因為在實際推演發生之前const U&被替換為。)U
回到 [temp.func.order],由于推導在兩個方向上都成功,第 2 段中提到的最終決勝局是一個模板是否比另一個模板更受約束。為此,我們向下滾動到第 6 段。適用的要點是 (6.2.2),根據該要點:
否則,如果template-parameter-list的對應template-parameter不等價([temp.over.link]),或者如果兩個模板之間位置對應的函式引數型別不同,則模板都不相同比另一個更專業。
請注意,在這種情況下,參考和 cv 限定符的剝離不適用,因為這只是作為演繹的一部分,我們不再進行演繹,因此位置對應的函式引數型別是Tand const T&,不一樣。因此,沒有一個模板比另一個模板更專業,這意味著最終的決勝局沒有選擇一個多載而不是另一個。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/452865.html
