首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这个clang代码不能用-std=c++20用clang 10编译

为什么这个clang代码不能用-std=c++20用clang 10编译
EN

Stack Overflow用户
提问于 2020-04-26 19:15:48
回答 1查看 800关注 0票数 10

下面的程序无法用clang10和-std=c++20编译

代码语言:javascript
复制
#include "clang/AST/ASTContext.h"
int main(){}

对于-std=c++17,它可以工作。

这是编译尝试输出(请注意,我对C++17中的链接器错误没有意见,因为我没有将所需的-l交给命令行)

代码语言:javascript
复制
clang++-10  toy.cc -I/usr/lib/llvm-10/include -std=c++20 -w
In file included from toy.cc:1:
In file included from /usr/lib/llvm-10/include/clang/AST/ASTContext.h:28:
In file included from /usr/lib/llvm-10/include/clang/AST/RawCommentList.h:14:
/usr/lib/llvm-10/include/clang/Basic/SourceManager.h:953:59: error: use of overloaded operator '!=' is ambiguous (with operand types 'llvm::DenseMapBase<llvm::DenseMap<const clang::FileEntry *, const clang::FileEntry *, llvm::DenseMapInfo<const clang::FileEntry *>, llvm::detail::DenseMapPair<const clang::FileEntry *, const clang::FileEntry *> >, const clang::FileEntry *, const clang::FileEntry *, llvm::DenseMapInfo<const clang::FileEntry *>, llvm::detail::DenseMapPair<const clang::FileEntry *, const clang::FileEntry *> >::iterator' (aka 'DenseMapIterator<const clang::FileEntry *, const clang::FileEntry *, llvm::DenseMapInfo<const clang::FileEntry *>, llvm::detail::DenseMapPair<const clang::FileEntry *, const clang::FileEntry *> >') and 'llvm::DenseMapBase<llvm::DenseMap<const clang::FileEntry *, const clang::FileEntry *, llvm::DenseMapInfo<const clang::FileEntry *>, llvm::detail::DenseMapPair<const clang::FileEntry *, const clang::FileEntry *> >, const clang::FileEntry *, const clang::FileEntry *, llvm::DenseMapInfo<const clang::FileEntry *>, llvm::detail::DenseMapPair<const clang::FileEntry *, const clang::FileEntry *> >::iterator')
      if (OverriddenFilesInfo->OverriddenFiles.find(File) !=
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
/usr/lib/llvm-10/include/llvm/ADT/DenseMap.h:1222:8: note: candidate function
  bool operator!=(const ConstIterator &RHS) const {
       ^
/usr/lib/llvm-10/include/llvm/ADT/DenseMap.h:1215:8: note: candidate function
  bool operator==(const ConstIterator &RHS) const {
       ^
/usr/lib/llvm-10/include/llvm/ADT/DenseMap.h:1215:8: note: candidate function (with reversed parameter order)
1 error generated.
clang++-10  toy.cc -I/usr/lib/llvm-10/include -std=c++17 -w
/usr/bin/ld: /tmp/toy-4396eb.o:(.data+0x0): undefined reference to `llvm::DisableABIBreakingChecks'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

备注:

  • 给这艘宇宙飞船贴上了标签,因为我不知道与C++20
  • 中的更改有关的标签不能减少这个示例,因为DenseMap是类中的怪物,我发现了类似的问题,解决方案是操作符缺少一个const限定符,这在这里似乎不是问题(我可以在源代码中看到const ),当我试图在一个简单的情况下得到类似的错误时,我没有得到一个错误。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-26 21:10:58

这个LLVM示例简化为:

代码语言:javascript
复制
struct iterator;

struct const_iterator {
    const_iterator(iterator const&);
};

struct iterator {
    bool operator==(const_iterator const&) const;
    bool operator!=(const_iterator const&) const;
};

bool b = iterator{} != iterator{};

在C++17中,这很好:我们只有一个候选,而且它是可行的(iterator可以转换为const_iterator,这样就可以工作了)。

在C++20,我们突然有了三个候选人。我将使用非会员语法写出它们,这样参数就更明显了:

代码语言:javascript
复制
bool operator==(iterator const&, const_iterator const&); // #1
bool operator==(const_iterator const&, iterator const&); // #2 (reversed #1)
bool operator!=(iterator const&, const_iterator const&); // #3

#2#1的反向候选。#3没有反向候选,因为只有主比较运算符(==<=>)才有反向候选。

现在,过载解析的第一步是执行转换序列。我们有两个类型为iterator的参数:对于#1,这是一个精确的匹配/转换。对于#2,这是转换/完全匹配。对于#3,这是完全匹配/转换的。这里的问题是,#1#2之间有一个“触发器”:在一个参数/参数对中,每个参数/参数对都更好,而在另一个参数/参数对中则更糟糕。这很模糊。即使从某种意义上说,#3是“更好的候选”,我们也不能得到那个非常模糊的转换序列意味着含糊的过载解析。

现在,gcc无论如何都会编译它(我不完全确定它在这里实现了哪些具体规则),甚至clang也不认为这是一个错误,只是一个警告(您可以用-Wno-ambiguous-reversed-operator禁用它)。在试图更优雅地解决这些情况方面,有一些正在进行的工作。

为了提供更多帮助,下面是LLVM示例的一个更直接的简化,以及我们如何为C++20修复它:

代码语言:javascript
复制
template <bool Const>
struct iterator {
    using const_iterator = iterator<true>;

    iterator();

    template <bool B, std::enable_if_t<(Const && !B), int> = 0>
    iterator(iterator<B> const&);

#if __cpp_impl_three_way_comparison >= 201902
    bool operator==(iterator const&) const;
#else
    bool operator==(const_iterator const&) const;
    bool operator!=(const_iterator const&) const;
#endif
};

在C++20中,我们只需要一个齐次比较算子。

这在C++17中是行不通的,因为希望支持iterator<false>{} == iterator<true>{}的情况:唯一的候选是iterator<false>::operator==(iterator<false>),您不能将const_iterator转换为iterator

但是在C++20中,这很好,因为在这个例子中,我们有两种选择:iterator<false>的相等运算符和iterator<true>的反向相等运算符。前者不可行,但后者是可行的,而且工作正常。

我们也只需要operator==。我们得到的operator!=是免费的,因为我们想要的是否定的平等。

或者,您仍然可以在C++17中将比较运算符编写为隐藏的朋友:

代码语言:javascript
复制
friend bool operator==(iterator const&, iterator const&);
friend bool operator!=(iterator const&, iterator const&);

这将使您获得与C++20相同的行为,方法是让来自两种类型的候选人参与其中(与C++20版本相比,只需编写一个额外的函数,而该函数必须是隐藏的朋友--不能是成员)。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61446642

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档