当前位置: 首页 > 知识库问答 >
问题:

GCC和clang(SFINAE)过载分辨率行为差异

昝宜
2023-03-14

GCC接受以下代码:

template <typename T>
struct meta
{
    typedef typename T::type type;
};

struct S {};

template <typename T>
typename meta<T>::type foo(T, S);

int foo(int, int);      

int main()
{
    foo(0, 0);
}

但是clang拒绝它并带有以下错误:

test.cpp:4:22: error: type 'int' cannot be used prior to '::' because it has no members
    typedef typename T::type type;
                     ^
test.cpp:10:10: note: in instantiation of template class 'meta<int>' requested here
typename meta<T>::type foo(T, S);
         ^
test.cpp:10:24: note: while substituting deduced template arguments into function template 'foo' [with T = int]
typename meta<T>::type foo(T, S);
                       ^

这似乎表明GCC和clang在重载解析期间执行某些操作的顺序有所不同。GCC似乎在尝试实例化模板候选者的返回类型之前抛弃了模板候选者,因为第二个参数(Svs.int)中的类型不匹配,而clang似乎反过来做。

谁是对的?

我相信这个问题对模板库的作者有着重要的意义。具体来说,如果clang是正确的,那么模板foo的作者将不得不做额外的工作,将错误转化为替换失败。

编辑:请注意,GCC和clang都拒绝了以下稍微简单的示例,但出现了类似的错误:

template <typename T>
struct meta
{
    typedef typename T::type type;
};

template <typename T>
typename meta<T>::type foo(T);

int foo(int);      

int main()
{
    foo(0);
}

建议GCC知道“只有函数类型及其模板参数类型的直接上下文中的无效类型和表达式才能导致推断失败”。本例与原始示例之间的区别在于原始示例中存在第二个html" target="_blank">函数参数,在此基础上,GCC甚至在尝试对返回类型执行替换之前就抛出了模板候选。我认为问题是,GCC是否正确地按照这个顺序进行操作,还是应该在考虑参数类型中的匹配之前尝试对返回类型执行替换。

更新:Luc Danton的回答让我相信clang拒绝代码是正确的。因此,我提交了一个GCC错误。

共有2个答案

冯永长
2023-03-14

C 03将此措辞作为通常称为SFINAE的规范的一部分(14.8.2模板参数扣除[temp.Decreate],第2段):

[...]如果模板参数或函数模板的函数类型中的替换导致无效类型,则类型推导失败。[...]

相比之下,C 11使用了以下措辞(14.8.2模板参数扣除[临时扣除],第8段):

如果替换导致无效类型或表达式,则类型推导失败。[...]只有函数类型及其模板参数类型的直接上下文中的无效类型和表达式才能导致推导失败。[...]

重点是我的。据我所知,C 11中的措辞得到了改进,明确地概述了什么应该导致SFINAE(所谓的软错误)和什么不应该导致SFINAE(硬错误)。这篇2008年的论文是当时正在进行的讨论的一个例子,它导致了当前的规则。

考虑到这一点,可能是这样的情况,根据C 03一个实现可能是正确的接受你的代码(甚至可能应该)。我怀疑C 11实现应该拒绝它但是:错误(int::type)是在meta的上下文中

戚逸清
2023-03-14

在这里,叮当声和g声都是正确的。

根据Luc Danton的回答,编译器可以推导出foo函数模板的T=int。然后,在将该值替换为foo声明的过程中,meta的隐式实例化

然而,[temp.inst]p7说:

如果重载解析过程可以在不实例化类模板定义的情况下确定要调用的正确函数,则未指定该实例化是否实际发生。

因为非模板foo调用中的参数完全匹配,所以编译器可以确定函数模板特化永远不会是最好的可行函数,因此不需要执行参数推导和替换。因此g不拒绝此代码是正确的。

 类似资料:
  • 问题内容: 当网站输出到客户端时,我正在尝试优化网站的大小。缓存时,我分别只有1.9MB和29KB。问题在于,第一次加载包含的图像对于移动设备而言并未经过优化。它具有1080p分辨率。 因此,我正在寻找一种方法,该方法允许我首先加载低分辨率版本(),一旦网站加载完毕,请使用高分辨率版本- 甚至分辨率接近所用设备的分辨率版本(或只是) 。 就像每个人都期望的那样,使用CSS设置背景。它应用于主体,整

  • 功能介绍 获取百度移动统计平台的全部屏幕分辨率列表 接口 https://openapi.baidu.com/rest/2.0/mtj/svc/config/getScreenList?access_token={ACCESS_TOKEN} 请求参数 参数名 类型 描述 样例 access_token string 用户登入后获取的token 1.a6b7dbd428f731035f771b8d

  • 好的,这里有一个奇怪的问题,我有问题(用gcc btw编译) 下面是用于命令提示的Mandelbrot分形生成器的源代码。我以前做过这项工作,我想加快自己的测试速度,看看我能以多快的速度生成命令提示符中实际生成Mandelbrot分形所需的代码。我经常这样做是为了给自己找点乐子 不管怎样,我遇到了一个新问题,我不太明白问题是什么。当分形呈现时,无论我设置了多少次迭代或什么转义值,它都将始终显示为椭

  • 我遇到了关于模板重载解析的有趣行为,在发布版本和调试版本之间有所不同。我希望能够理解编译器/链接器使用的规则,这些规则使它以这种方式运行。< br >我尝试了一下,这是我想到的: S. h S.cpp main.cpp 我尝试编译相应的编译单元(S.cpp.o,main.cpp.o和生成的二进制文件)。我发现结果完全取决于main.cpp.o编译的优化水平。 使用 时,输出为 。 使用 时,输出为

  • 我试图使用clang和gcc交叉编译一个项目,但在使用时,我发现了一些奇怪的差异,例如。 现在,当涉及NAN时,我期望类型行为,但clang和gcc给出不同的结果: 当我使用它时,_mm_max_ps做了预期的事情。我尝试过使用,,但似乎没有效果。有什么想法可以让编译器之间的行为相似吗? 这里是锁销连接

  • 注意:Photoshop 提供了已更新的“图像大小”对话框。请参阅调整图像大小,以了解更多信息。 关于像素尺寸和打印图像分辨率 像素尺寸测量了沿图像的宽度和高度的总像素数。分辨率是指位图图像中的细节精细度,测量单位是像素/英寸 (ppi)。每英寸的像素越多,分辨率越高。一般来说,图像的分辨率越高,得到的印刷图像的质量就越好。两幅相同的图像,分辨率分别为 72 ppi 和 300 ppi;套印缩放比