struct S
{
vector<int> v;
void method()
{
begin(v);
}
};
上面的代码段编译得很好,因为ADL直到我添加
auto begin() { return begin(v); }
到类声明。此时,C ++会忘记ADL,而是更喜欢甚至没有可行重载的S::begin
,从而产生错误
error: no matching function for call to ‘S::begin(std::vector<int>&)’ begin(v);
有没有解决这个问题?我问,因为在阅读Why use non-member begin and end functions in C++11?之后,我开始在所有地方使用begin()
和end()
个免费函数来保持一致性,但现在我在定义自己的begin()
和{之后遇到了冲突{1}}方法。
答案 0 :(得分:4)
正如评论S::begin
中所提到的,隐藏std::begin
。您可以通过键入std::begin
或明确调用S
将using std::begin
带入std::begin
的范围。
struct S
{
std::vector<int> v;
void method()
{
using std::begin;
begin(v);
}
auto begin() { using std::begin; return begin(v); }
};
答案 1 :(得分:2)
您使用begin
作为非限定名称和非限定名称查找
...检查下面描述的范围,直到找到至少一个任何类型的声明,此时查找停止,不再检查其他范围。
从您的成员函数的角度来看,提供名称begin
的第一个范围是类范围,因此它会填充该范围的重载集,并停止查找。
只有在此名称查找阶段之后,它才会尝试选择其中一个重载集,并确定没有匹配项。编译器没有返回并从下一个范围开始搜索,它只是放弃了。
您的选择是:
使用现有的容器成员函数而不是自由函数(这比下面明确限定的版本略微冗长)
auto begin() { return v.begin(); }
使用限定名称
auto begin() { return ::std::begin(v); }
使用using std::begin;
忽略那一个,我忘了你不能在using
的课堂范围内引入非会员名称。
将正确的重载注入到成员函数体本身的较窄范围内,因此搜索停在那里
auto begin() { using std::begin; return begin(v); }
首先停止提供begin
成员函数,而是将非成员begin
重载添加到封闭名称空间。这是更现代的和,可以避免查找问题。
namespace N {
struct S { std::vector<int> v; };
std::vector<int>::iterator begin(S& s) { return s.v.begin(); }
// and end, cbegin, etc. etc.
}