具有相同参数的命名空间中的函数和函数之间的歧义
Ambiguity between function and function in namespace with same argument
谁能解释一下为什么 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;
}
但是,g++ 7.5.0 和 clang 6.0.0 都抱怨函数调用不明确
(error: call of overloaded ‘f(A::B&)’ is ambiguous
) 无论编译器标志和优化如何。
这是 argument-dependent lookup 的示例。
即使 ::main
在全局命名空间中,A::f
也可以在不使用完全限定名称的情况下调用,因为它是在其参数的命名空间 A
中查找的,A::B
。因此,::f
和 A::f
之间存在歧义。
要解决歧义,您需要调用 A::f(b)
(就像您所做的那样)或 ::f(b)
.
对于这个函数调用表达式
f(b);
编译器找到在全局命名空间中声明的名称f
。另一方面,使用依赖于参数的查找,编译器还查找声明了 class B
的命名空间 A
,并找到名称为 f
的函数。这两个函数都不是被调用的最佳候选者。所以有歧义。
除了使用函数的限定名称来避免歧义之外,您还可以通过以下方式抑制参数依赖查找
( f )( b );
参数依赖查找对于搜索友元函数非常有用,如果它们仅在授予友谊的 class 中定义,则它们是不可见的。
这是一个演示程序
#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;
}
程序输出为
10
如果参数依赖查找不存在,则无法调用朋友 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;
}
即使指定限定名N::f
,也无法调用友元函数f
。对于这个程序,编译器会发出一个错误,指出 ‘f’ is not a member of ‘N’
。要使函数可见,您还需要在 class 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;
}
谁能解释一下为什么 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;
}
但是,g++ 7.5.0 和 clang 6.0.0 都抱怨函数调用不明确
(error: call of overloaded ‘f(A::B&)’ is ambiguous
) 无论编译器标志和优化如何。
这是 argument-dependent lookup 的示例。
即使 ::main
在全局命名空间中,A::f
也可以在不使用完全限定名称的情况下调用,因为它是在其参数的命名空间 A
中查找的,A::B
。因此,::f
和 A::f
之间存在歧义。
要解决歧义,您需要调用 A::f(b)
(就像您所做的那样)或 ::f(b)
.
对于这个函数调用表达式
f(b);
编译器找到在全局命名空间中声明的名称f
。另一方面,使用依赖于参数的查找,编译器还查找声明了 class B
的命名空间 A
,并找到名称为 f
的函数。这两个函数都不是被调用的最佳候选者。所以有歧义。
除了使用函数的限定名称来避免歧义之外,您还可以通过以下方式抑制参数依赖查找
( f )( b );
参数依赖查找对于搜索友元函数非常有用,如果它们仅在授予友谊的 class 中定义,则它们是不可见的。
这是一个演示程序
#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;
}
程序输出为
10
如果参数依赖查找不存在,则无法调用朋友 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;
}
即使指定限定名N::f
,也无法调用友元函数f
。对于这个程序,编译器会发出一个错误,指出 ‘f’ is not a member of ‘N’
。要使函数可见,您还需要在 class 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;
}