我有一个名为f
的成员,同时还有一个名为f
的通用免费函数。
自由函数f
旨在从另一个成员(下面称为g
)调用。
class A{};
int f(A const& a){return 5;} // generic free f
template<class T>
struct B{
void f() const{} // member f
int g(){
T a;
auto i = f(a) + 1; // here (cannot resolve f)
return i;
}
};
int main(){
B<A> b;
int j = b.g();
assert(j == 6);
}
事实证明,我的编译器(GCC和clang)无法解析对f
的调用。
error: no matching function for call to ‘B::f(A&)’
auto i = f(a) + 1; ^
note: candidate: void B::f() const
void f() const{} ^
note: candidate expects 0 arguments, 1 provided
这当然是因为它与成员f
混淆了。
然而,只有::f
才有意义。
如果我要强制使用会员功能,我可以说this->f
或B::f
。
但是我知道没有相反的语法,即强制自由函数::f
或实际上某些外部解析到ADL给出的f
并禁用成员函数(类似notthis->f
})。
我可以使用using ::f
:
... int g(){
T a;
using ::f;
auto i = f(a) + 1;
return i;
} ...
但是,这不是通用的,因为我不知道哪个命名空间T
属于我,我想要通用代码。 (这里是::
,但对于T = A
,但对于其他名称空间中的其他类,我不知道。)
例如,类B<ns::C>
应编译为:
namespace ns{
class C{};
int f(C const& a){return 5;} // genetic free f
}
当然我可以重命名所有内容以避免冲突,但这不是一个可接受的解决方案,假设同时拥有名为f
的free和member函数是有意义的。
这是GCC和clang的错误,是语言的缺陷还是我错过了一些指明不使用成员函数的明显方法?
(该示例使用C ++ 11,但该问题适用于任何版本的C ++)。
感谢@JohnZwinck,这是当前的解决方法
class A{};
int f(A const& a){return 5;} // genetic free f
class nonmember{
protected:
template<class TT> static decltype(auto) _f(TT&& t){return f(std::forward<TT>(t));}
};
template<class T>
struct B : private nonmember{
void f() const{} // member f
int g(){
T a;
auto i = _f(a) + 1;
return i;
}
};
答案 0 :(得分:2)
这是GCC和clang的错误,这是语言的缺陷吗?
以上都不是。在语言中,与名称匹配的成员函数是最佳匹配的设计决策。如果你想避免它们,可以通过中间自由函数调用:
template<class T>
int call_f(const T& arg){
return f(arg);
}
template<class T>
struct B{
void f() const{}
int g(){
T a;
auto i = call_f(a) + 1;
return i;
}
};