C++ 编译器无法找到函数(与命名空间相关)
我正在使用 Visual Studio 2008 进行 C++ 编程作业。 我们提供了定义以下命名空间层次结构的文件(这些名称只是为了这篇文章的目的,我知道“命名空间 XYZ-NAMESPACE”是多余的):
(MAIN-NAMESPACE){
a bunch of functions/classes I need to implement...
(EXCEPTIONS-NAMESPACE){
a bunch of exceptions
}
(POINTER-COLLECTIONS-NAMESPACE){
Set and LinkedList classes, plus iterators
}
}
MAIN-NAMESPACE 内容被分割在一堆文件之间,并且一些我不明白操作员的原因<< 对于 Set 和 LinkedList 来说,它们完全位于 MAIN-NAMESPACE 之外(但位于 Set 和 LinkedList 的头文件内)。 这是 Set 版本:
template<typename T>
std::ostream& operator<<(std::ostream& os,
const MAIN-NAMESPACE::POINTER-COLLECTIONS-NAMESPACE::Set<T>& set)
现在问题是:我有以下数据结构:
Set A
Set B
Set C
double num
它被定义为位于 MAIN-NAMESPACE 内的类中。 当我创建该类的实例并尝试打印其中一组时,它告诉我: 错误 C2679:二进制 '<<' :找不到采用“const MAIN-NAMESPACE::POINTER-COLLECTIONS-NAMESPACE::Set”类型的右侧操作数的运算符(或者没有可接受的转换)
但是,如果我只编写一个 main() 函数,并且创建集合 A,填充它,然后使用运算符 - 它可以工作。
知道有什么问题吗? (注意:我尝试了使用和包含我能想到的任何组合)。
I'm working in Visual Studio 2008 on a C++ programming assignment. We were supplied with files that define the following namespace hierarchy (the names are just for the sake of this post, I know "namespace XYZ-NAMESPACE" is redundant):
(MAIN-NAMESPACE){
a bunch of functions/classes I need to implement...
(EXCEPTIONS-NAMESPACE){
a bunch of exceptions
}
(POINTER-COLLECTIONS-NAMESPACE){
Set and LinkedList classes, plus iterators
}
}
The MAIN-NAMESPACE contents are split between a bunch of files, and for some reason which I don't understand the operator<< for both Set and LinkedList is entirely outside of the MAIN-NAMESPACE (but within Set and LinkedList's header file).
Here's the Set version:
template<typename T>
std::ostream& operator<<(std::ostream& os,
const MAIN-NAMESPACE::POINTER-COLLECTIONS-NAMESPACE::Set<T>& set)
Now here's the problem: I have the following data structure:
Set A
Set B
Set C
double num
It's defined to be in a class within MAIN-NAMESPACE. When I create an instance of the class, and try to print one of the sets, it tells me that:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const MAIN-NAMESPACE::POINTER-COLLECTIONS-NAMESPACE::Set' (or there is no acceptable conversion)
However, if I just write a main() function, and create Set A, fill it up, and use the operator- it works.
Any idea what is the problem? (note: I tried any combination of using and include I could think of).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
奇怪的是,尽管将与类型关联的自由函数放入不同的命名空间是一种不好的做法,但全局命名空间声明始终是可见的。
我唯一能想到的是,在
MAIN-NAMESPACE
中具有相同名称的声明会隐藏全局命名空间中的声明 - 难道没有operator<<
,可能是完全不相关的类型,在MAIN-NAMESPACE
中? 如果是这样,您应该通过在MAIN-NAMESPACE
中使用 ::operator<< 声明来修复该问题。 例子:Strange - even though putting free functions associated with a type to a different namespace is a bad practice, the global namespace declarations are always visible.
The only thing I can think of is that declaration with the same name in
MAIN-NAMESPACE
would shadow the one in the global namespace - isn't there anoperator<<
, possibly for totally unrelated type, inMAIN-NAMESPACE
? If so, you should fix that byusing ::operator<<
declaration inMAIN-NAMESPACE
. Example:好吧,我明白了。
jpalecek 关于存在另一个运算符的直觉<< 命名空间中的内容是正确的(显然我忘记将其注释掉)。
命名空间的查找规则首先在函数调用的命名空间中开始搜索,并搜索封闭的命名空间,一直到全局命名空间(如果未找到匹配项,则执行参数相关查找)。 然而,如果一路上它发现了一些与operator<<匹配的东西,它就会停止搜索,不管这些函数中使用的类型可能不兼容,就像这里的情况一样。
解决方案是将其包含到 MAIN-NAMESPACE 中(我不允许这样做),或者使用“using ::operator<<”从全局命名空间导入它。
OK I figured this out.
jpalecek's intuition about there existing another operator<< in the namespace was correct (apparently I forgot to comment it out).
The lookup rules for namespaces first start the search in the function call's namespace and search up the enclosing namespaces, right up to the global namespace (then it does the Argument dependent lookup if no match is found). However, if along the way it finds some match for operator<<, it stops the search, regardless of the fact that the types used in those functions may be incompatible, as was the case here.
The solution is either to include it into the MAIN-NAMESPACE (which I'm not allowed to), or import it from the global namespace with "using ::operator<<".
尝试显式调用该函数?
Try calling the function explicitly?
正如 SoaBox 指出的那样,尝试显式调用它。
供您参考,如果您希望调用隐藏在当前命名空间中的全局函数,请在函数前面添加 :: 以绕过本地函数并调用全局函数。
As SoaBox pointed out, try calling it explicitly.
For your information, if you wish to call a global function which has been hidden in the current namespace precede the function with :: to bypass the local function and call the global function.
是的,那确实有效!
那么让我们看看我是否正确:调用运算符<< 的原因 从 main() 函数起作用是因为我位于全局名称空间中(就像运算符<<)。
从我实现的类调用时失败的原因是该类位于非全局命名空间中,并且其中没有将编译器指向全局命名空间的变量。
Yes, that does work!
So let's see if I got this right: the reason invoking the operator<< from a main() function worked is because I was in the global namespace (as was operator<<).
The reason it failed when invoking from the class I implemented is because the class was in a not global namespace and there were no variables in it that pointed the compiler towards the global namespace.
好的,人们要求提供具体的示例,所以这里是代码的相关部分。
//免责声明:在极少数情况下,我大学的某人看到了这一点,在提交文件中遇到了它,并决定我复制了它或其他东西,我的学号是311670137
这是头文件Set.h:
这是我在中定义的另一个文件:
这是来自主文件的:
reportRegisteredStations 定义为:
OK people asked for a specific examples, so here's the relevant part of the code.
//Disclamer: in the slim case someone from my uni sees this, encounters it in the submission file, and decides I copied it or something, my student number is 311670137
This is the header file Set.h:
This is what I defined in a different file:
And here's from the main:
reportRegisteredStations is defined as:
这对我有用
This works for me
更正:以下文本基于 g++ 系列编译器的经验。 在对答案发表评论后,我重新阅读了标准(其中规定 ADL 将用于常规名称查找,并且常规名称查找应该找到运算符<<)。 我还尝试过 comeau 编译器(我所知道的最符合标准的编译器)并找到了符号。 这似乎是 g++ 的问题(尝试过版本 3.3、4.1、4.3)。
原始答案:
搜索Koening查找(技术上ADL:参数依赖查找)。
简短的答案是,如果您有以下类:
流插入运算符应定义为:
函数或运算符应定义在与其所采用的参数之一相同的命名空间中。 (*)
当编译器找到函数调用时,例如:
它将尝试在当前命名空间(调用位置)或 c1 和 c2 类型的封闭命名空间中查找 f 函数( namespace1,namespace2::namespace3),但它不会在搜索中尝试其他命名空间。
(*) 在这种情况下,您几乎只能使用 test 命名空间,因为不允许您向 std 命名空间添加函数(仅限模板特化)。
原始帖子结束。
即使如之前所述,这可能只是编译器的问题,但这是常见用法,建议在与类型本身相同的命名空间中定义对用户定义类型进行操作的所有自由函数。
CORRECTION: The text below is based on experience with the g++ family of compilers. After the comment to the answer I have reread the standard (which states that ADL will be used over regular name lookup, and regular name lookup should find the operator<<). I have also tried with comeau compiler (the most standard compliant compiler I know of) and the symbol is found. It seems as a problem with g++ (tried versions 3.3, 4.1, 4.3).
Original answer:
Search for Koening lookup (technically ADL: Argument dependent lookup).
The short answer is that if you have the following class:
the stream insertion operator should be defined as:
Functions or operators should be defined in the same namespace as one of the arguments that it takes. (*)
When the compiler finds a function call such as:
it will try to find the f function in the current namespace (at the place of call) or in the enclosing namespaces of c1 and c2 types (namespace1, namespace2::namespace3), but it will not try other namespaces in the search.
(*) In this case, you are pretty much limited to the test namespace, as you are not allowed to add a function to the std namespace (only template specializations).
End of original post.
Even if as commented before this may just be a problem with the compiler, it is common usage and recommended to define all free functions that operate on a user defined type in the same namespace as the type itself.