具有相同参数的命名空间中的函数和函数之间的歧义

rc4*_*559 14 c++ namespaces function-call argument-dependent-lookup

任何人都可以解释为什么A::f(const B& b)和之间存在歧义f(const A::B& b)。我认为代码对意图非常明确。

#include <iostream>

namespace A
{
  class B
  {
  protected:
    double value_;
  public:
    B() : value_(15.0) {}
    double getValue() const {return value_;}
  };

  void f(const B& b)
  {
    std::cout << "f(b) = " << b.getValue() << std::endl;
  }
}

void f(const A::B& b)
{
  std::cout << "Other f(b) = " << b.getValue() << std::endl;
}

int main()
{
  A::B b;
  A::f(b);
  f(b);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

然而,error: call of overloaded ‘f(A::B&)’ is ambiguous无论编译器标志和优化如何,g++ 7.5.0 和 clang 6.0.0 都会抱怨函数调用不明确 ( )。

Jan*_*tke 17

这是一个参数依赖查找的例子。

即使::main在全局命名空间中,A::f也可以在不使用完全限定名称的情况下调用,因为它是在A其参数的命名空间中查找的,A::B. 因此,::f和之间存在歧义A::f

要解决歧义,您需要调用A::f(b)(如您所做的那样)或::f(b).


Vla*_*cow 7

对于这个函数调用表达式

f(b);
Run Code Online (Sandbox Code Playgroud)

编译器找到f在全局命名空间中声明的名称。另一方面,使用参数相关查找,编译器还查找声明A 类的命名空间,B并查找名称为 的函数f。这两个函数都不是被调用的最佳候选者。所以有歧义。

除了使用函数的限定名称来避免歧义之外,您还可以通过以下方式抑制参数相关查找

( f )( b );
Run Code Online (Sandbox Code Playgroud)

参数相关查找对于搜索友元函数非常有用,如果友元函数仅在授予友元关系的类中定义,则这些友元函数是不可见的。

这是一个演示程序

#include <iostream>

namespace N
{
    

    class A
    {
    private:
        int x;
    
    public:
        A( int x ) : x( x ) {}
    
        friend std::ostream & operator <<( std::ostream &os, const A &a )
        {
            return os << a.x;
        }
    };
}

int main()
{

    N::A a( 10 );
    
    std::cout << a << '\n';
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

程序输出是

10
Run Code Online (Sandbox Code Playgroud)

如果参数相关查找不存在,则operator <<无法调用朋友,因为即使在命名空间 N 中也找不到它

考虑以下程序。

#include <iostream>

namespace N
{
    class A
    {
    private:
        int x;
    
    public:
        A( int x ) : x( x ) {}
    
        friend void f( int x )
        {
            A a( x );
            
            std::cout << a.x << '\n';
        }
    };
}

int main()
{
    N::f( 10 );
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

f即使指定了限定名,也不能调用友元函数N::f。对于这个程序,编译器会发出一个错误提示‘f’ is not a member of ‘N’。要使该函数可见,您还需要在 A 类之外声明它,例如

#include <iostream>

namespace N
{
    class A
    {
    private:
        int x;
    
    public:
        A( int x ) : x( x ) {}
    
        friend void f( int x )
        {
            A a( x );
            
            std::cout << a.x << '\n';
        }
    };
    
    void f( int ); // make the function visible
}

int main()
{
    N::f( 10 );
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)