如何解决使用文字 0 和指针调用重载函数的歧义

Posted

技术标签:

【中文标题】如何解决使用文字 0 和指针调用重载函数的歧义【英文标题】:How to resolve ambiguity of call to overloaded function with literal 0 and pointer 【发布时间】:2011-06-04 08:59:33 【问题描述】:

我很确定这一定已经在这里了,但我没有找到太多关于如何解决这类问题的信息(没有在通话中进行强制转换):

给定两个重载,我希望带有文字 0 的函数调用始终调用 unsigned int 版本:

void func( unsigned int ) 
    cout << "unsigned int" << endl;


void func( void * ) 
    cout << "void *" << endl;


func( 0 ); // error: ambiguous call

我明白为什么会发生这种情况,但我不想一直写 func( 0u ) 甚至 func( static_cast(0) )。所以我的问题是:

1) 通常有推荐的方法吗?

2)按照以下方式进行操作有什么问题吗?这样做的原因是什么?

void func( unsigned int ) 
    cout << "unsigned int" << endl;


template <typename T>
void func( T * ) 
    static_assert( std::is_same<T, void>::value, "only void pointers allowed" );
    cout << "void *" << endl;


func( 0 ); // calls func( unsigned int )!

【问题讨论】:

【参考方案1】:

您在 2) 中所做的工作有效,并且可能是更好的方法。

在您不想更改函数的情况下,您可以进行显式转换以向编译器提示:

func((void *) 0);
func((unsigned int) 0);

【讨论】:

【参考方案2】:

我建议您查看 C++0x 中的空指针(请参阅this)。它定义了一个表示任何类型的空指针的类。您刚刚给出的示例实际上是促使将 nullptr_t(类)/nullptr(值)包含到 C++0x 中的一个示例。它实际上让您可以通过在需要 unsigned int 版本时输入 0 和在需要另一个版本时输入 nullptr 来消除此调用的歧义。

你可以在一个小的实用程序类中实现这个技巧,直到你的编译器支持它(或者如果你的编译器实现了下一个标准的这一部分,就使用它)。

【讨论】:

"当想要 unsigned int 版本时输入 0" - 但我认为 func(0) 在 C++0x 中仍然模棱两可。 intunsigned int 和 null-pointer-constant 到 void*std::nullptr_t 都是转换,并且在重载解析方面都比另一个更好。 一开始我也是这么想的,但我建议你参考这个:devx.com/cplus/10MinuteSolution/35167/1954(阅读“看看 nullptr 如何优雅地解决前面显示的重载解决问题:”部分) nullptr 是一个类似指针的对象,但这并不意味着 ints 不再隐式转换为指针。这意味着当您写nullptr 时,您实际上并没有以迂回的方式写0 @Max,我同意,但 Alp 提供的链接另有说明。它说 0 将不再转换为指针(或至少具有较低的重载优先级),但我怀疑这实际上会破坏很多代码。 谢谢,但这对我没有帮助,因为我希望始终将纯文字 0 传递给非指针重载。实际目的是一个重载的 operator[] ,它允许按 index 进行索引,也可以按 char * (对于字符串文字)进行索引,其中 nullptr 永远不是有效的参数。【参考方案3】:

1) 通常有推荐的方法吗?

是的,我会按照您在 2) 中的方式进行操作。我认为为什么 2) 有效没有任何更深层次的含义。 int 类型根本不匹配 T*,因此它无法找到 T。因此它将忽略模板。

【讨论】:

非常简单的解释......现在你这么说了,它的工作原理就很明显了。【参考方案4】:

1) 通常有推荐的方法吗?

问题只是文字0int,而不是unsigned int,并且存在从intunsigned int 以及从intvoid* 的有效转换。我不能说有一个推荐的方法来处理这个问题。除了您已经找到的方式之外,您还可以添加另一个重载:

void func(int i) 

    assert(i >= 0);
    return func(static_cast<unsigned int>(i));

2)按照以下方式进行操作有什么问题吗?这样做的原因是什么?

模板技巧之所以有效,是因为解析对重载且具有模板版本的函数的调用的规则旨在优先使用重载函数的非模板版本。

【讨论】:

以上是关于如何解决使用文字 0 和指针调用重载函数的歧义的主要内容,如果未能解决你的问题,请参考以下文章

使用函数指针解决函数重载二义性调用问题

使用 + (unary plus) 为 lambda 解决函数指针和 std::function 上的模棱两可的重载

函数重载歧义使用 - Xcode 12.5

java中重载覆盖和隐藏三者的区别分析

Java8:与 lambdas 和重载方法的歧义

kotlin 中的重载分辨率歧义错误