gpt4 book ai didi

c++ - GCC 和 clang (SFINAE) 之间的重载解析行为差异

转载 作者:IT老高 更新时间:2023-10-28 22:04:39 26 4
gpt4 key购买 nike

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 在重载解析期间执行某些操作的顺序有所不同。由于第二个参数(S vs. int)before 试图实例化返回,GCC 似乎抛弃了候选模板候选模板的类型,而 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 知道“只有在函数类型及其模板参数类型的直接上下文中的无效类型和表达式才会导致推导失败”。此示例与原始示例之间的区别在于原始示例中存在第二个函数参数,基于此,GCC 在尝试对返回类型执行替换之前就抛出了候选模板。我认为问题是,GCC 按该顺序执行操作是否正确,或者它是否应该在考虑参数类型匹配之前尝试对返回类型执行替换。

更新:Luc Danton 的回答让我相信 clang 拒绝代码是正确的。我有相应的filed a GCC bug .

最佳答案

Clang 和 g++ 在这里都是正确的。

根据 Luc Danton 的回答,允许编译器推断 T = int对于foo函数模板。然后,在将该值替换为 foo 的声明期间,meta<int> 的隐式实例化是必需的,它会导致替换的直接上下文之外的错误(因此 SFINAE 不适用)。所以 Clang 拒绝这个代码是正确的。

但是,[temp.inst]p7 说:

If the overload resolution process can determine the correct function to call without instantiating a class template definition, it is unspecified whether that instantiation actually takes place.

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

关于c++ - GCC 和 clang (SFINAE) 之间的重载解析行为差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12015938/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com