在OS X Mavericks中编译时的模糊函数

时间:2014-03-03 01:26:53

标签: c++ compilation osx-mavericks ambiguous

我一直在努力在我的Macbook 10.9.2上安装GDL,编译时我遇到了很多问题。最终,我经历了很多形式的问题:

/Downloads/gdl-0.9.4/src/basic_fun.cpp:6415:14: error: call to 'isalpha' is ambiguous
        if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') 
             ^~~~~~~
/usr/include/ctype.h:218:1: note: candidate function
isalpha(int _c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/cctype:60:38: note: 
      candidate function
inline _LIBCPP_INLINE_VISIBILITY int isalpha(int __c) {return __libcpp_isalpha(__c);}

通过将foo()更改为::foo()可以很容易地修复它们,但它似乎有些笨拙。即使Homebrew安装了像wxmac这样的东西,问题仍然存在。我不得不改变其中一个标题以使其工作 - 与模糊函数相同的问题。有趣的是isdigit()问题不会发生 - 有意义吗?

问题似乎是Xcode的libc ++与/ usr / include中的标题之间存在冲突。有一个简单的方法吗?

当我在我女朋友的Mountain Lion机器上编译GDL时,这不是问题。

1 个答案:

答案 0 :(得分:2)

很难确定,但这听起来非常像我一直在追逐的问题,在这种情况下是tolower()。我怀疑你在某处包含一个标题,它定义了各种字符处理例程的宏,如isalpha(),tolower()等。在我的例子中,这是Python包含文件pyport.h,它被一些Boost代码包含在内。接下来发生的事情非常复杂,但以下任何工作都要解决它:

  • 删除任何使用命名空间std'声明。
  • 使用:: tolower()等。
  • 使用std :: tolower()等,但有效,但感觉不对。
  • 重新订购包含声明,因此cctype包含在任何内容之前 像pyport.h一样将tolower()等定义为宏。
  • 只需在代码中尽早添加#include cctype即可。

以下内容摘自我撰写的一篇相当冗长的报告,描述了我遇到的问题。即使它不是你的问题,听起来好像它肯定是相关的。

基本上,以下示例程序不能编译,至少在我的Yosemite系统上,它安装了Boost并运行Python 2.7。其他具有不同Python版本的OS X机器可能没问题。

#include <boost/python.hpp>
#include <boost/asio/ssl.hpp>

int main() { 
    return 0;
}

你抱怨两个错误抱怨&#39; tolower&#39;暧昧。这两个错误基本相同,如下所示:

In file included from demo1.cpp:3:
In file included from /usr/local/include/boost/asio/ssl.hpp:23:
In file included from /usr/local/include/boost/asio/ssl/rfc2818_verification.hpp:99:
/usr/local/include/boost/asio/ssl/impl/rfc2818_verification.ipp:146:14: error: 
      call to 'tolower' is ambiguous
    else if (tolower(*p) == tolower(*h))

/usr/include/ctype.h:292:1: note: candidate function
tolower(int _c)

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/cctype:149:38: note: 
      candidate function
inline _LIBCPP_INLINE_VISIBILITY int tolower(int __c) {return __libcpp_t...

原因相当复杂,但潜在的问题来自Python包含文件pyport.h如何与各种字符处理例程如tolower()混淆。基本上,它重新定义tolower()作为宏来解决与字符宽度有关的问题。这个宏然后混淆了标准cctype包含文件也尝试处理tolower()的方式。结果是全局命名空间中的tolower()和std命名空间中的另一个。如果在使用命名空间std&#39;的范围内使用tolower(),最终会出现问题。适用。

此前的示例缩小为触发问题的一些最小代码。 pyport.h文件包含ctype.h和wctype.h,然后有一个#define for tolower()。接下来的代码是导致问题的那种东西,即包括wchar.h和cctype,然后使用命名空间std&#39;以及对tolower()的引用(这是Boost,rfc2818_verification.ipp的作用,但任何执行相同操作的代码都会触发问题)。

#include <ctype.h>
#include <wctype.h>
#define tolower(c) towlower(btowc(c))

#include <wchar.h>
#include <cctype>
char GetLower (const char c) {
   using namespace::std;
   return tolower(c);
}

int main() { 
   return 0;
}

好的,这里发生了什么?问题基本上是pyport.h将tolower()定义为宏,结合cctype包含文件句柄tolower(),当tolower()被定义为宏时。

pyport.h正在尝试处理Python与最新版本的tolower()等问题,这些问题适用于宽字符,因为这会破坏一些东西。它通过将tolower()定义为明确适用于窄字符的宏来处理此问题。这大部分时间都有效。

cctype正试图处理普通tolower()例程简单定义为宏的系统上发生的事情,而不是实际例程。在这种情况下,它在std ::中定义了一个例程,它执行了tolower()的操作(使用宏来执行此操作)并将其替换为该宏。它的作用基本上是:

_LIBCPP_BEGIN_NAMESPACE_STD

#ifdef tolower
inline _LIBCPP_INLINE_VISIBILITY int __libcpp_tolower(int __c) {return tolower(__c);}
#undef tolower
inline _LIBCPP_INLINE_VISIBILITY int tolower(int __c) {return __libcpp_tolower(__c);}
#else  // tolower
using ::tolower;
#endif  // tolower

_LIBCPP_END_NAMESPACE_STD

在tolower只是普通全局命名空间中的例程的机器上,它只是发出一个使用:: tolower&#39;。这是OS X上的正常情况。

这种结合导致问题的方式是,在这种情况下,在包含cctype的时候,tolower()已被定义为宏,但是出于私人目的,而不是因为那个&#39;是定义它的正常方式。结果是全局命名空间中有一个tolower()(以正常方式由ctype.h定义)和std :: namespace中的一个tolower()(由cctype定义,它被pyport声明的宏定义所欺骗) .H)。

如果您使用tolower()而没有明确的命名空间,那么这不是问题,因为它会获取正常的全局tolower()。如果您明确使用std :: tolower()或:: tolower(),那就没问题,因为您得到了您所要求的内容。如果你有一个使用命名空间std&#39;这只是一个问题。然后只使用tolower(),因为你告诉编译器它可以在std中查找tolower,它会这样做并找到一个。但它也会找到正常的全球tolower()。然后它不知道该做什么,那就是你的错误。

如何解决?

这取决于问题是否出现在您可以更改的代码中,或者代码是否可以(或者不应该)像Boost包含文件一样。如果您可以更改代码:

o不要使用命名空间std;&#39; - 无论如何,这不是一个好主意。

o使用:: tolower()。然后就没有歧义了。

o使用std :: tolower(),尽管只有在cctype定义时才有效;通常它不会。

如果您无法更改触发问题的代码文件:

o重新排序包含文件,以便在包含pyport.h的文件之前包含cctype。那么cctype并没有将tolower()的定义看作一个宏而且很好。

o尽可能早地将#include cctype放在代码中。然后在pyport.h混淆之前处理它,之后的任何包含都将被忽略。这可能是最简单的修复。