簡體   English   中英

為什么 gcc 和 clang 在聚合初始化中給出不同的結果?

[英]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; }

gccclang都接受上面的代碼。 但是, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM