使用nullptr作为参数的函数重载解析

时间:2019-02-22 03:48:16

标签: c++ templates overload-resolution ambiguous-call

请考虑以下代码。尽管fun的两个重载都接受指针,但是将nullptr传递给fun不会导致任何编译错误。而非常相似的函数bun无法编译。当我使用i 打印参数typeid(i).name()的类型时(在修改代码以使其打印出来之后),我得到了相同的类型,只需int* 。解决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

1 个答案:

答案 0 :(得分:1)

事实上,GCC accepts your code, but Clang does not。因此,一开始该通话是否模棱两可并不明显。

您问在fun情况下,什么规则可以解决歧义?海湾合作委员会显然认为有这样一条规则。我认为GCC正在应用的规则是[over.match.best] /1.7规则,该规则更倾向于使用更专业化的功能模板而不是相对不那么专业化的模板。

[temp.func.order]中描述了确定哪个功能模板比另一个功能模板更具体的过程,并在this SO answer中进行了详细说明。但是,您会注意到,如本问题所述,在尝试将此过程应用于fun的两个重载时,我们遇到了一个问题,即需要用唯一的合成类型来代替U第一个重载将需要具有一个名为sth的成员,并且该成员的性质未指定,尽管人类可能很清楚,第二个fun重载的推论必须成功,而不管什么sth的类型是,编译器可能无法证明它。

这是CWG 1157。由于此问题仍未解决,尚无建议的解决方案,因此我不了解WG21是否打算使此重载解决方案成功。