![](/img/trans.png)
[英]Why does std::locale(“”).name() give different results on clang and gcc?
[英]Why do gcc and clang give different results in aggregate initialization?
#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給出了預期的 output 3
; 除了 clang 給出的意外output 1
之外。
參見: https://godbolt.org/z/YKnxWah1a
相關問答:為什么 Clang 12 拒絕以 C++20 方式初始化聚合?
在這種情況下哪個是正確的?
U
是一種聲稱可轉換為任何其他類型的類型。 並且“任何其他類型”包括提供給f
模板的任何T
因此,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>
到其基類之一的隱式轉換。 但是,基於基本 class 轉換的重載解決方案優先考慮與 inheritance 圖中的參數類型更接近的基類。 因此, X<3>
優先於X<2>
,即使兩者都可用。
因此,根據 C++20 的規則和重載決議,3 應該是正確的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.