以下程式:
#include <type_traits>
template<typename T, bool b>
struct S{
S() = default;
template<bool sfinae = true,
typename = std::enable_if_t<sfinae && !std::is_const<T>::value>>
operator S<T const, b>() { return S<T const, b>{}; }
};
template<typename T, bool b1, bool b2>
void f(S<const std::type_identity_t<T>, b1>,
// ^- T in non-deduced context for func-param #1
S<T, b2>)
// ^- T deduced from here
{}
int main() {
S<int, true> s1{};
S<int, false> s2{};
f(s1, s2);
}
被 GCC (11.2) 接受,但被 Clang (13) 和 MSVC (19.latest) 拒絕,全部用于-std=c 20/ /std:c 20( DEMO )。
- 什么編譯器在這里是正確的?
uj5u.com熱心網友回復:
這由[temp.deduct.call] 管理,特別是/4:
通常,推導程序試圖找到模板引數值,使推導的結果
A與A(在A如上所述轉換型別之后)相同。但是,存在三種情況會有所不同: [...]
在 OP 的示例中,AisS<const int, true>和(轉換后的)Ais S<int, int>,并且這 [三種] 情況都不適用于此處,這意味著推導失敗。
我們可以通過調整程式來對此進行試驗,使得推導A與轉換的A差異屬于三種情況之一;說[temp.deduct.call]/4.3
- 如果
P是一類與P具有形式簡單模板id,然后轉化A可以是一個派生類D的推導的A。[...]
#include <type_traits>
template<typename T, bool b>
struct S : S<const T, b> {};
template<typename T, bool b>
struct S<const T, b> {};
template<typename T, bool b1, bool b2>
void f(S<const std::type_identity_t<T>, b1>, S<T, b2>){}
int main() {
S<int, true> s1{};
S<int, true> s2{};
f(s1, s2);
}
該程式被所有三個編譯器(DEMO)正確接受。
因此,GCC 很可能在這里存在錯誤,因為上述錯誤是可診斷的(不是格式錯誤的 NDR)。由于我找不到這些問題的開放錯誤,我已提交:
- 錯誤 103333 - [accepts-invalid] 函式模板引數推導不兼容的“轉換 A”/“推導 A”對
我們可能還注意到[temp.arg.explicit]/7包含一個特殊情況,允許隱式轉換將引數型別轉換為函式引數型別:
如果引數型別不包含參與模板引數推導的模板引數,則將對函式引數執行隱式轉換 ([conv]) 以將其轉換為相應函式引數的型別。
這并沒有在OP的例子適用,雖然,作為(功能)引數型別S<const std::type_identity_t<T>, b1>還包含(非型別)模板引數b1,它參與了模板引數推導。
但是在以下程式中:
#include <type_traits>
template<typename T>
struct S{
S() = default;
template<bool sfinae = true,
typename = std::enable_if_t<sfinae && !std::is_const<T>::value>>
operator S<T const>() { return S<T const>{}; }
};
template<typename T>
void f(S<const std::type_identity_t<T>>, S<T>) {}
int main() {
S<int> s1{};
S<int> s2{};
f(s1, s2);
}
(函式)引數型別是A<std::type_identity_t<T>>,并且其中唯一的模板引數T不參與該引數 - 引數對(P/ A)的模板引數推導。因此,[temp.arg.explicit]/7 確實適用于此并且程式格式良好。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/366262.html
上一篇:C 多型和模板化介面
