【问题标题】:Is clang's c++11 support reliable?clang 的 c++11 支持可靠吗?
【发布时间】:2015-03-01 03:44:22
【问题描述】:

我在尝试混合 clang(Apple LLVM 版本 6.0 (clang-600.0.56)(基于 LLVM 3.5svn,目标:x86_64-apple-darwin14.0.0)、c++11 和 CGAL 时遇到了一个有趣的问题(通过 MacPorts)。

看来我是否调用std::vector<>::reserve 将决定我的程序是否会编译。

我已将问题精简为一个最小示例(与 CGAL 示例一样最小):

#include <vector>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_triangle_primitive.h>

// CGAL::Epeck works fine, suggesting the problem is in CGAL::Epick
typedef CGAL::Epick Kernel;
typedef CGAL::Triangle_3<Kernel> Triangle_3; 
typedef typename std::vector<Triangle_3>::iterator Iterator;
typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
typedef typename Tree::Point_and_primitive_id Point_and_primitive_id;
typedef CGAL::Point_3<Kernel>    Point_3;

template <typename BKernel>
void A()
{
  const CGAL::AABB_tree<
    CGAL::AABB_traits<BKernel, 
      CGAL::AABB_triangle_primitive<BKernel, 
        typename std::vector<CGAL::Triangle_3<BKernel> >::iterator
      >
    >
  > tree;
  Point_and_primitive_id pp = tree.closest_point_and_primitive(Point_3());
}

void B()
{
  std::vector<Triangle_3> T;
#ifdef MAGIC
  T.reserve(0);
#endif
  return A<Kernel>();
}

发行:

clang++ -std=c++11 -c example.cpp -I/opt/local/include

编译失败。给出如下错误:

    In file included from example.cpp:1:
    In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:265:
    In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__bit_reference:15:
    In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:626:
    In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/utility:157:
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tuple:228:60: error: 
          no member named 'value' in 'std::__1::is_convertible<const CGAL::Point_3<CGAL::Epick> &,
          CGAL::Point_3<CGAL::Epick> >'
                                   is_convertible<_Tp0, _Up0>::value &&
                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__tuple:242:14: note: 
          in instantiation of template class 'std::__1::__tuple_convertible_imp<true, std::__1::__tuple_types<const
          CGAL::Point_3<CGAL::Epick> &, const CGAL::Vector_3<CGAL::Epick> &>,
          std::__1::__tuple_types<CGAL::Point_3<CGAL::Epick>, CGAL::Vector_3<CGAL::Epick> > >' requested here
        : public __tuple_convertible_imp<tuple_size<typename remove_reference<_Tp>::type>::value ==

但是,如果我对std::vector::reserve 进行魔术调用,这确实可以编译,发出:

clang++ -std=c++11 -c example.cpp -I/opt/local/include -DMAGIC

或者通过禁用 c++11

clang++ -c example.cpp -I/opt/local/include
  1. 这是 CGAL 还是 clang 中的错误?
  2. 对于这种不稳定的编译器行为有什么解释?
  3. 有没有一种干净的方法来避免这种情况(希望没有真正改变模板或函数原型设置,因为我需要解决方案来适应我的大型项目)。

【问题讨论】:

  • 这似乎是 XCode 对 is_convertible 的定义中的侥幸,但出现这样的错误是如此不可能,以至于我的大脑拒绝接受它的存在。您知道正在使用哪个标准库吗?这与我的 clang 使用的不同。我不知道我的是什么,但上面写着“Copyright (C) 2001-2013 Free Software Foundation, Inc.”
  • Clang 似乎有 libc++,而我有 libstdc++ en.wikipedia.org/wiki/Standard_Template_Library#Implementations
  • 如果我添加标志-stdlib=libc++ 那么情况不会改变。相反,如果我添加 -stdlib=libstdc++ 则不会编译任何版本,我会收到类似 error: no template named 'forward' in namespace 'std'; 的错误
  • 我推测您的libstdc++ 已经过时了。我希望检查代码以查看是否可以确定问题,但是您和我的代码不同。也许其他人可以研究它
  • llvm.org/bugs/show_bug.cgi?id=22085 希望我们很快就能知道错误在哪里。

标签: c++ c++11 compiler-errors cgal clang++


【解决方案1】:

由于 Apple 的 GCC 已过时(2007 年的最新 GPL v2 版本,GCC 4.2.1)且 C++11 功能不完整(因此随附提供的 libstdc++),您可以通过 MacPorts 安装更现代版本的 GCC( sudo port install gcc48sudo port install gcc49),这将为您提供更现代的 libstdc++ 版本。我测试了你的代码:

/opt/local/bin/g++-mp-4.8 -std=c++11 -c example.cpp -I/opt/local/include

编译成功。

如果您更喜欢此解决方案并想要更简洁的编译器调用;您可以使用 gcc_select 和命令(在我的例子中为 gcc48)将 MacPorts 的 GCC 设置为默认值:

sudo port select --set gcc mp-gcc48

只有一次。然后,你可以编译它只是

g++ -std=c++11 -c example.cpp -I/opt/local/include

在新的终端会话中。

【讨论】:

  • 感谢您的解释。这是我的典型设置,但我现在的目标是让我的项目使用 mac 上的内置 clang 进行编译:所以我不想切换编译器。 C++11 的哪个特性缺少这个例子?
  • 谢谢。查看问题中的 cmets,当您使用 Apple 的 libstdc++ 时,似乎缺少 std::forward。长期(但希望有回报)的方法是忽略 MacPorts 并使用内置的 clang 自己编译 CGAL 及其所有依赖项。我自己从来没有这样做过,如果你这样做,我会很想了解你的经历。另一种方法可能是将这些问题报告给 MacPorts 的维护人员,并等待他们更改 CGAL 的编译脚本及其依赖项。
  • 谢谢。那么,这到底是 CGAL 中的错误还是苹果的 libstdc++ 中的错误,CGAL 不知何故绊倒了?
  • 我会说这要么是 MacPorts 没有编译 CGAL 及其与 Apple 的 clang 和 libc++ 的所有依赖项,要么是 Apple 的 libstdc++ 太旧的“问题”(这不完全是错误,而是许可证问题与使用 GPLv3 许可的较新版本的 libstdc++ 以及 GPLv3 中的限制阻止 Apple 将其包含在 OS X 中有关)。
猜你喜欢
  • 2011-12-20
  • 2012-11-01
  • 2012-05-23
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多