GCC和clang之间的过载分辨率行为差异(SFINAE) [英] Overload resolution behaviour difference between GCC and clang (SFINAE)

查看:236
本文介绍了GCC和clang之间的过载分辨率行为差异(SFINAE)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

GCC接受以下代码:

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

structure S {};

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

int foo(int,int);

int main()
{
foo(0,0);但是clang拒绝它,出现以下错误:










$ b

  test.cpp:4:22:error:type'int'不能在'::'之前使用,因为它没有成员
typedef typename T :: type type;
^
test.cpp:10:10:note:在这里请求的模板类'meta< int>'的实例化中
typename meta :: type foo(T, ;
^
test.cpp:10:24:注意:同时将推导的模板参数替换为函数模板'foo'[使用T = int]
typename meta< T& T,S);
^

这似乎暗示了GCC和clang操作。 GCC似乎抛出了模板候选,因为第二个参数中的类型不匹配( S int )<



谁是对的? 之前试图实例化模板候选的返回类型, p>

我相信这个问题对模板库的作者有重要的影响。具体来说,如果clang是正确的,模板 foo 的作者必须做额外的工作才能将错误转换为替换失败。



EDIT :请注意,以下稍微简单的示例被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是否正确地按顺序做事情,或者它应该尝试在返回类型之前执行替换,然后再考虑匹配参数类型。



UPDATE :Luc Danton的回答确信我ang是正确的拒绝代码。因此,我已提交了GCC错误



每个Luc Danton的答案,一个编译器允许推导<$ c函数模板的<$ c> T = int 。然后,在将该值替换为 foo 的声明中,需要隐式实例化 meta ,并且它导致在替换的直接上下文之外的错误(因此SFINAE不适用)。所以Clang拒绝这个代码是正确的。



但是, [temp.inst] p7 说:


如果重载解析过程可以确定正确的函数,而不需要实例化类模板定义,那么它是否指定实例化是否实际发生。


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


GCC accepts the following code:

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);
}

But clang rejects it with the following error:

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);
                       ^

This seems to suggest a difference in the order in which GCC and clang do certain operations during overload resolution. GCC seems to throw out the template candidate because of the type mismatch in the second parameter (S vs. int) before trying to instantiate the return type of the template candidate, while clang seems to do it the other way around.

Who is right?

I believe this question has important implications for the authors of template libraries. Specifically, if clang is right, the author of the template foo would have to do extra work to turn the error into a substitution failure.

EDIT: Note that the following slightly simpler example is rejected by both GCC and clang, with similar errors:

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);
}

suggesting that GCC knows that "only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure". The difference between this example and the original is the presence of the second function parameter in the original example, on the basis of which GCC throws out the template candidate before it even gets to trying to perform substitution on the return type. I think the question is, whether GCC is correct to do things in that order, or should it be trying to perform substitution on the return type before considering matches in argument types.

UPDATE: Luc Danton's answer convinced me that clang is correct to reject the code. I have accordingly filed a GCC bug.

解决方案

Both Clang and g++ are correct here.

Per Luc Danton's answer, a compiler is permitted to deduce T = int for the foo function template. Then, during the substitution of that value into the declaration of foo, the implicit instantiation of meta<int> is required, and it results in an error outside the immediate context of the substitution (so SFINAE does not apply). So Clang is correct to reject this code.

However, [temp.inst]p7 says:

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.

Because the non-template foo is an exact match for the arguments in the call, a compiler could determine that a function template specialization will never be the best viable function, and so need not perform argument deduction and substitution. Therefore g++ is correct to not reject this code.

这篇关于GCC和clang之间的过载分辨率行为差异(SFINAE)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆