#include <iostream>
struct U
{
template<typename T>
operator T();
};
template<unsigned I>
struct X : X<I - 1> {};
template<>
struct X<0> {};
template<typename T>
constexpr auto f(X<4>) -> decltype(T(U{}, U{}, U{}, U{}), 0u) { return 4u; }
template<typename T>
constexpr auto f(X<3>) -> decltype(T(U{}, U{}, U{}), 0u) { return 3u; }
template<typename T>
constexpr auto f(X<2>) -> decltype(T(U{}, U{}), 0u) { return 2u; }
template<typename T>
constexpr auto f(X<1>) -> decltype(T(U{}), 0u) { return 1u; }
template<typename T>
constexpr auto f(X<0>) -> decltype(T{}, 0u) { return 0u; }
struct A
{
void* a;
int b;
double c;
};
int main() { std::cout << f<A>(X<4>{}) << std::endl; }
上面的代碼被gcc和clang接受。但是,gcc給出了預期的輸出3;除了clang1給出的意外輸出。
見:https : //godbolt.org/z/YKnxWah1a
相關問答:為什么 Clang 12 拒絕以 C 20 的方式初始化聚合?
在這種情況下哪個是正確的?
uj5u.com熱心網友回復:
U是一種宣告可轉換為任何其他型別的型別。“任何其他型別”包括T提供給f模板的任何內容。
因此,1 始終是潛在的合法過載;SFINAE 允許它存在。
A是 3 個元素的集合。因此,它可以通過包含 0 到 3 個元素的初始化串列進行初始化。C 20 允許聚合使用建構式語法進行聚合初始化。
因此,3、2、1 和 0 都是潛在的合法多載;SFINAE 允許它們存在。在 C 20 之前的規則下,這些都不是聚合初始化,因此它們(除了 1,由于 的上述屬性而起作用)都不U是有效的 SFINAE 多載。
Clang 尚未實作 C 20 的聚合初始化規則,因此就 Clang 而言,唯一可用的多載是 X<1>。
對于功能更完整的 C 編譯器,問題是:根據 C 的多載決議規則,哪種多載更好?
好吧,所有可用的多載都涉及從引數型別X<4>到其基類之一的隱式轉換。但是,基于基類轉換的多載決議優先考慮更接近繼承圖中引數型別的基類。因此,即使兩者都可用,X<3>優先級更高X<2>。
因此,根據 C 20 的規則和多載決議,3 應該是正確的答案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/397884.html
上一篇:帶有遞回數C 的直角三角形模式
下一篇:解構式找不到我的命名空間方法
