首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么gcc和clang在聚合初始化方面给出了不同的结果?

为什么gcc和clang在聚合初始化方面给出了不同的结果?
EN

Stack Overflow用户
提问于 2021-12-29 17:04:31
回答 1查看 111关注 0票数 1
代码语言:javascript
复制
#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,而不是clang给出的意外输出1

请参阅:https://godbolt.org/z/YKnxWah1a

相关问答:Why does Clang 12 refuse to initialize aggregates in the C++20 way?

在本例中哪个是正确的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-29 17:29:31

U是一种声称可兑换到任何其他类型的类型。“任何其他类型”包括向T模板提供的任何f

因此,1总是一个潜在的合法超载;SFINAE允许它存在。

A是由3种元素组成的集合。因此,它可以通过包含0到3个元素的初始化程序列表进行初始化。C++20允许聚合使用构造函数语法进行聚合初始化。

因此,3、2、1和0都是潜在的合法超载;SFINAE允许它们存在。在预C++20规则下,所有这些规则都不是聚合初始化,因此它们中没有一个是有效的SFINAE重载(保存1,因为U的上述属性而工作)。

到目前为止,Clang还没有实现C++20的聚合初始化规则,因此就Clang而言,唯一可用的重载是X<1>。

对于功能更全面的C++编译器,问题是:根据C++的过载解析规则,哪种重载更好?

好的,所有可用的重载都涉及从参数类型X<4>到它的一个基类的隐式转换。但是,基于基类转换的重载解析使更接近继承图中参数类型的基类具有优先权。因此,X<3>优先于X<2>,尽管两者都是可用的。

因此,根据C++20的规则和过载解决方案,3应该是正确的答案。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70522630

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档