繁体   English   中英

为什么以下代码使用 clang 而不是 gcc 编译

[英]Why does the following code compile using clang but not gcc

#include <iostream>
#include <unordered_map>
#include <string>

struct tree_node {
  // tree_node() : attrib_val{"null"} {}
  std::unordered_map<std::string, tree_node> child;
};
int main(int argc, char const *argv[])
{
  return 0;
}

这段代码在我的带有 clang 的 mac 上编译得很好:

$ g++ --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

$ g++ -std=c++11 test.cpp
$ 

在我的 linux 机器上,使用 gcc 9.1.0,我收到以下错误:

In file included from /usr/um/gcc-9.1.0/include/c++/9.1.0/bits/stl_algobase.h:64,
                 from /usr/um/gcc-9.1.0/include/c++/9.1.0/bits/char_traits.h:39,
                 from /usr/um/gcc-9.1.0/include/c++/9.1.0/ios:40,
                 from /usr/um/gcc-9.1.0/include/c++/9.1.0/ostream:38,
                 from /usr/um/gcc-9.1.0/include/c++/9.1.0/iostream:39,
                 from test.cpp:1:
/usr/um/gcc-9.1.0/include/c++/9.1.0/bits/stl_pair.h: In instantiation of ‘struct std::pair<const std::__cxx11::basic_string<char>, tree_node>’:
/usr/um/gcc-9.1.0/include/c++/9.1.0/ext/aligned_buffer.h:91:28:   required from ‘struct __gnu_cxx::__aligned_buffer<std::pair<const std::__cxx11::basic_string<char>, tree_node> >’
/usr/um/gcc-9.1.0/include/c++/9.1.0/bits/hashtable_policy.h:233:43:   required from ‘struct std::__detail::_Hash_node_value_base<std::pair<const std::__cxx11::basic_string<char>, tree_node> >’
/usr/um/gcc-9.1.0/include/c++/9.1.0/bits/hashtable_policy.h:264:12:   required from ‘struct std::__detail::_Hash_node<std::pair<const std::__cxx11::basic_string<char>, tree_node>, true>’
/usr/um/gcc-9.1.0/include/c++/9.1.0/bits/hashtable_policy.h:2016:13:   required from ‘struct std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const std::__cxx11::basic_string<char>, tree_node>, true> > >’
/usr/um/gcc-9.1.0/include/c++/9.1.0/bits/hashtable.h:173:11:   required from ‘class std::_Hashtable<std::__cxx11::basic_string<char>, std::pair<const std::__cxx11::basic_string<char>, tree_node>, std::allocator<std::pair<const std::__cxx11::basic_string<char>, tree_node> >, std::__detail::_Select1st, std::equal_to<std::__cxx11::basic_string<char> >, std::hash<std::__cxx11::basic_string<char> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >’
/usr/um/gcc-9.1.0/include/c++/9.1.0/bits/unordered_map.h:105:18:   required from ‘class std::unordered_map<std::__cxx11::basic_string<char>, tree_node>’
test.cpp:7:46:   required from here
/usr/um/gcc-9.1.0/include/c++/9.1.0/bits/stl_pair.h:215:11: error: ‘std::pair<_T1, _T2>::second’ has incomplete type
  215 |       _T2 second;                /// @c second is a copy of the second object
      |           ^~~~~~
test.cpp:5:8: note: forward declaration of ‘struct tree_node’
    5 | struct tree_node {

由于某种原因,它不喜欢将tree_node作为unordered_map中的值。

这是[res.on.functions]/2.5未定义的行为:

[如果] 在实例化模板组件或评估概念时将不完整的类型 ([basic.types]) 用作模板参数,则效果未定义,除非该组件特别允许。

这是一个令人讨厌的情况,我基本上必须证明这个答案是否有效,但我发现标准中没有提到允许您在std::map中使用不完整类型的异常的地方。 因此,这个程序可以做任何事情。 特别是,虽然 Clang 现在可以编译它,但它可能在将来的任何时候停止工作,而且编译的代码map专业化也有可能无法正常工作 某些容器,尤其是std::vector ,有一个子句允许它们在正确的条件下以不完整的类型实例化。 但是这种情况是未定义的行为,因此编译器没有义务警告您或错误。 以某种方式更改您的程序以避免这种情况。 我相信以下内容是合法的,不会强迫您存储太多额外的指针。

struct tree_node {
  std::unique_ptr<std::unordered_map<std::string, tree_node>> child;
};

std::unique_ptr是一般禁止规则的一个例外——可以将它实例化为不完整的类型(但它的一些成员并不那么松懈)。 我相信这意味着std::unordered_map<std::string, tree_node>不需要在tree_node的定义中完成std::unique_ptr的专业化需要完成,因此std::unordered_map特化没有被触发并且 UB 被避免,因为tree_node不需要是完整的。 请注意,您仍然可以毫无顾虑地编写构造函数、函数、析构函数等,因为所有这些定义都隐式移出 class 定义并在其之后,并且在 class 定义结束后tree_node变得完整。

改变:

struct tree_node {
  // tree_node() : attrib_val{"null"} {}
  std::unordered_map<std::string, tree_node> child;
};

至:

struct tree_node {
  // tree_node() : attrib_val{"null"} {}
  std::unordered_map<std::string, tree_node *> child;
};

使编译问题 go 消失。 它是否对你想要的有任何反映?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM