4

考虑下面的代码。fun尽管接受指针的两个重载,传递nullptrfun都不会导致任何编译错误。然而,非常相似的函数bun无法编译。当我i使用打印参数的类型时typeid(i).name() (在修改代码只是为了打印它之后)我得到相同的类型,只是int*. 在 case 中解决歧义fun但失败的规则是什么bun?提前致谢!

#include <iostream>

struct Foo {
    int sth;
};

template< class U>
void fun(decltype(U::sth)* i){
    std::cout << "1" << std::endl;
}

template< class U>
void fun(U* i){
    std::cout << "2" << std::endl;
}

void bun(decltype(Foo::sth)* i){
    std::cout << "3" << std::endl;
}

void bun(Foo* i){
    std::cout << "4" << std::endl;
}

int main ( )
{
    fun<Foo>(nullptr);
    // bun(nullptr); --> call of overloaded 'bun(std::nullptr_t)' is ambiguous        
    return 0;          
}
-----------------------
output : 1
4

1 回答 1

1

好吧,事实上,GCC 接受您的代码,但 Clang 不接受。因此,起初,调用是否模棱两可并不明显。

你问什么规则解决了fun案件中的歧义;GCC 显然认为有这样的规则。我想 GCC 正在应用的规则是规则 [over.match.best]/1.7,它更喜欢更专业的功能模板而不是不太专业的功能模板。

[temp.func.order] 中描述了确定哪个函数模板比​​另一个更专业的过程,并在这个 SO answer中进行了彻底解释。但是,您会注意到,当尝试将此过程应用于fun此问题中 as 的两个重载时,我们遇到了一个问题,即需要U在第一个重载中替换的唯一合成类型需要有一个名为 的成员sth,并且未指定此成员的性质,尽管人们可能清楚第二个fun重载中的推导必须成功,而不管sth' 的类型是什么,编译器可能无法证明这一点。

这是CWG 1157。由于这个问题仍然悬而未决,没有提议的解决方案,我不知道 WG21 是否打算让这个过载解决方案成功或不成功。

于 2019-02-22T04:23:59.937 回答