【问题标题】:Calling a function with a non-const pointer reolves to a template function over a function taking a pointer to const使用解析为模板函数的非 const 指针调用函数,而不是使用指向 const 的指针的函数
【发布时间】:2011-06-23 23:35:02
【问题描述】:

以下代码是在 g++ 4.1.2 和 g++ 4.4.4 上编译的。两者都给出了 cmets 中记录的结果。

int f(const int * a)
{
   return 0;
}

template<typename A>
int f(A a)
{
   return 1;
}

int main()
{
    int x;
    // return f(&x); // returns 1
    return f((const int *)&x); // returns 0
}

似乎可以归结为f(int *) 的调用解析为f&lt;int *&gt;(int *),而不是预期的f(const int *)。我发现这令人震惊且完全不直观。

这是 g++ 中的错误,C++ 的一个黑暗角落,还是由于某种原因我失踪了?如果它不是错误,那么它背后的理论或逻辑是什么?有没有关于这个问题的安全做法?

【问题讨论】:

  • f(int)f(const int) 就 ANSI c++ 编译器而言是相同的原型
  • 对,但是f(int *)f(const int *)/f(int const *)不一样
  • +1 用于提供最小、完整的示例程序。请参阅 sscce.org 了解为什么这是个好主意。
  • @sehe “也许”?我认为您误读了该链接上的讨论。 "foo(int *const a)" 接受一个指向 int 的 const 指针。在此处的示例中,“f(const int * a)”接受指向 const-int 的指针。

标签: c++


【解决方案1】:

对于实例化的模板f&lt;int *&gt;,不需要转换(int *->const int *),所以这是一个更好的匹配——实际上,它是一个精确匹配,它只会输给非模板化的精确匹配,这就是第二次调用时发生的情况。

“更好匹配”规则的完整说明可在 C++ 标准的 §13.3.3 中找到。

【讨论】:

    【解决方案2】:

    那么,在f(&amp;x) 调用的情况下,为什么要调用“预期”函数的 const 版本?

    如您所知,参数类型是int *。所以f(int *) 版本的函数比f(const int *) 版本更匹配,因为在前者中,参数类型完全匹配。编译器看到了从模板生成f(int *) 的机会,并抓住了这个机会。这就是它在 C++ 中的工作方式。

    如果模板版本与非模板版本一样好,则非模板版本通常会胜出。但是在这种情况下,模板版本明显更好,模板版本胜出。

    显然您希望编译器选择该函数的非模板版本。为什么?

    【讨论】:

    • 我预计它会因为一个微不足道的隐式 const 转换而获胜。对我来说,在考虑模板之前总是会升级指针类型,这似乎是明智的。也许有一个例子说明为什么这不是一个好主意。
    • @Roland : 无转换 > 重载解析中的微不足道的转换。
    • @Roland:假设您有两种方法来执行操作。它是破坏性的(就其论点而言)。在const 版本中,因此您需要先执行参数的副本,这显然效率较低。示例:T&amp;&amp; operator+(T&amp;&amp;, T const&amp;)T operator+(T const&amp;, T const&amp;) 更高效。
    • 在这种情况下,我同意只是因为它们都是模板。我的意思是在考虑任何模板之前我期望隐式 const 转换。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    • 2016-08-17
    相关资源
    最近更新 更多