我正在把所有的C ++ Windows应用程序移动到Ubuntu Linux。 此应用程序在Windows 7操作系统上的Visual Studio 2015社区上运行良好。 但是,在Ubuntu Linux上的代码块中运行时会出现错误。 我已经复制了我正在使用以下简单的Person
类的错误消息。
错误消息:'comparePersonAge'未在此范围内声明
#ifndef Person_h #define Person_h #include <string> class Person { private: int age; std::string name; public: Person(int a, std::string n) : age(a), name(n) {} int getAge() { return age; } std::string getName() { return name; } inline friend bool comparePersonAge(const Person& p1, const Person& p2) { return p1.age < p2.age; } }; #endif
main.cpp中
#include <iostream> #include <algorithm> #include <vector> #include "Person.h" int main() { Person p1(93, "harold"); Person p2(32, "james"); Person p3(67, "tracey"); std::vector<Person> v; v.push_back(p1); v.push_back(p2); v.push_back(p3); std::sort(v.begin(), v.end(), comparePersonAge); std::cout << v[0].getAge() << " " << v[1].getAge() << " " << v[2].getAge() << std::endl; }
在Windows机器上,输出如预期的那样是32 67 93
。 在Linux上,错误消息如上所述。
注意:别人的名字DJR在这篇文章中讨论了这个问题: Friend函数未在此范围内声明错误 。 不过,他的解释是非常模糊的,不要跟着他的脚步走。
他写:
以前的评论应该读取:这是Linux端的一个错误。 代码应该按照书面的方式工作。 我现在有编码在Windows端的代码,当我把它移到Linux端我得到同样的错误。 显然你在Linux端使用的编译器不会在头文件中看到/使用friend声明,因此会出现这个错误。 通过在函数的使用(例如:可能在函数callback赋值中使用)之前简单地移动C ++文件中的friend函数的定义/实现,这解决了我的问题,并且也应该解决你的问题。
在函数的使用之前,我不知道通过在C ++文件中移动友元函数的定义意味着什么。 这是什么意思呢?
friend
关键字的用途是为访问规则( protected
和private
)制定一个例外规定,给予不允许的成员类或函数访问权限。
所以你可以声明和定义你的类声明之外的comparePersonAge()
函数,并且在声明中使用friend
关键字来赋予函数对私有成员的访问权限,具体age
。
标准7.3.1.2/3:
名称空间中首先声明的每个名称都是该名称空间的成员。 如果非本地类中的朋友声明首先声明了一个类或函数,那么朋友类或函数是最内层的名字空间的成员。 直到在该名称空间范围内(在授予友谊的类定义之前或之后)提供匹配声明之前,通过无限制查找(3.4.1)或合格查找(3.4.3)才能找到该朋友的名字。 如果调用好友函数,则可以通过名称查找找到其名称,该名称查找考虑了与函数参数类型(3.4.2)相关联的名称空间和类的函数 。 如果朋友声明中的名称既不是限定名也不是模板标识,并且声明是函数或详细类型说明符,则确定实体是否先前已声明的查找不应考虑最内层封闭名称空间之外的任何作用域。
好了,经过与@Niall的小讨论之后,我意识到MSVC ++在这种情况下是错误的,因为ADL只发生在函数调用表达式中,而且因为std::sort
只是传递函数的名字,比如comparePersonAge
,所以当时没有函数comparePersonAge
调用std::sort
。 因此,我认为GCC和Clang是正确的
几点。
inline
。 所以,如果你想通过常规查找来访问它,请在封闭的名称空间中声明它。
演示