【发布时间】:2020-01-05 22:42:15
【问题描述】:
首先是一些背景。正如 C++17 标准所说:
[vector.overview]/3 如果分配器满足分配器完整性要求 17.6.3.5.1,则在实例化向量时可以使用不完整类型 T。 T 应在所产生的向量特化的任何成员被引用之前完成。
我已经尝试了3个场景in this repo(代码复制在底部):
- 声明包含不完整向量类型的类(默认 ctor/dtor)并在同一头文件中定义
- 使用 a.h 编译包括:
clang++ test.cpp --std=c++17 - 声明了包含不完整向量类型的类(默认 ctor/dtor)并在头文件和源文件中定义 编译失败
- 使用 b.h 编译包括:
clang++ test.cpp b.cpp --std=c++17
- 使用 b.h 编译包括:
- 包含不完整向量类型的类在头文件和源文件中声明和定义(ctor/dtor 显式定义)
- 使用 b.h 编译包括:
clang++ test.cpp c.cpp --std=c++17
我的问题是,为什么在第二种情况下编译失败,而不是第一种或第三种情况?如果按照标准说引用了 std::vector 的成员,那么为什么在仅标头的情况下没有引用它?这个引用的成员是什么?有什么方法可以在不触及默认关键字或前向声明的情况下编译第二种情况?
附注我尝试过 clang 9.0.0 和 Apple clang 11.0.0 版。
main.cpp
// #include "a.h" // << OK
#include "b.h" // << Compile error
// #include "c.h" // << OK
int main(int argc, char const *argv[])
{
Bar b;
return 0;
}
a.h
#include <vector>
struct Foo;
struct Bar
{
Bar() = default;
virtual ~Bar() = default;
std::vector<Foo> foos;
};
struct Foo
{
};
b.h
#include <vector>
struct Foo;
struct Bar
{
Bar() = default;
~Bar() = default;
std::vector<Foo> foos;
};
b.cpp
#include "b.h"
struct Foo
{
};
c.h
#include <vector>
struct Foo;
struct Bar
{
Bar();
~Bar();
std::vector<Foo> foos;
};
c.cpp
#include "c.h"
struct Foo
{
};
Bar::Bar(){}
Bar::~Bar(){}
有错误情况的编译输出:
(py3) cpp/vector_incomplete > clang++ test.cpp b.cpp --std=c++17
In file included from test.cpp:2:
In file included from ./b.h:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:427:68: error:
arithmetic on a pointer to an incomplete type 'Foo'
__alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__soon_to_be_end));
^ ~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:370:29: note: in
instantiation of member function 'std::__1::__vector_base<Foo, std::__1::allocator<Foo> >::__destruct_at_end' requested here
void clear() _NOEXCEPT {__destruct_at_end(__begin_);}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:464:9: note: in
instantiation of member function 'std::__1::__vector_base<Foo, std::__1::allocator<Foo> >::clear' requested here
clear();
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:496:5: note: in
instantiation of member function 'std::__1::__vector_base<Foo, std::__1::allocator<Foo> >::~__vector_base' requested here
vector() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
^
./b.h:6:5: note: in instantiation of member function 'std::__1::vector<Foo, std::__1::allocator<Foo> >::vector' requested here
Bar() = default;
^
./b.h:3:8: note: forward declaration of 'Foo'
struct Foo;
^
In file included from test.cpp:2:
In file included from ./b.h:1:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:275:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__bit_reference:16:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:644:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1817:55: error:
invalid application of 'sizeof' to an incomplete type 'Foo'
{_VSTD::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));}
^~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1555:14: note: in
instantiation of member function 'std::__1::allocator<Foo>::deallocate' requested here
{__a.deallocate(__p, __n);}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:465:25: note: in
instantiation of member function 'std::__1::allocator_traits<std::__1::allocator<Foo> >::deallocate' requested here
__alloc_traits::deallocate(__alloc(), __begin_, capacity());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:496:5: note: in
instantiation of member function 'std::__1::__vector_base<Foo, std::__1::allocator<Foo> >::~__vector_base' requested here
vector() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
^
./b.h:6:5: note: in instantiation of member function 'std::__1::vector<Foo, std::__1::allocator<Foo> >::vector' requested here
Bar() = default;
^
./b.h:3:8: note: forward declaration of 'Foo'
struct Foo;
^
In file included from test.cpp:2:
In file included from ./b.h:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:373:52: error:
arithmetic on a pointer to an incomplete type 'Foo'
{return static_cast<size_type>(__end_cap() - __begin_);}
~~~~~~~~~~~ ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:465:57: note: in
instantiation of member function 'std::__1::__vector_base<Foo, std::__1::allocator<Foo> >::capacity' requested here
__alloc_traits::deallocate(__alloc(), __begin_, capacity());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:496:5: note: in
instantiation of member function 'std::__1::__vector_base<Foo, std::__1::allocator<Foo> >::~__vector_base' requested here
vector() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
^
./b.h:6:5: note: in instantiation of member function 'std::__1::vector<Foo, std::__1::allocator<Foo> >::vector' requested here
Bar() = default;
^
./b.h:3:8: note: forward declaration of 'Foo'
struct Foo;
^
In file included from test.cpp:2:
In file included from ./b.h:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:873:54: error:
arithmetic on a pointer to an incomplete type 'const std::__1::vector<Foo, std::__1::allocator<Foo> >::value_type'
(aka 'const Foo')
__annotate_contiguous_container(data(), data() + capacity(),
~~~~~~ ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:552:9: note: in
instantiation of member function 'std::__1::vector<Foo, std::__1::allocator<Foo> >::__annotate_delete' requested here
__annotate_delete();
^
./b.h:6:5: note: in instantiation of member function 'std::__1::vector<Foo, std::__1::allocator<Foo> >::~vector' requested here
Bar() = default;
^
./b.h:3:8: note: forward declaration of 'Foo'
struct Foo;
^
4 errors generated.
【问题讨论】:
-
失败代码的代码列表以及编译器错误会很有用。
-
问题应该直接包含相关代码,而不是链接后面。见How to Ask。
-
stackoverflow.com/q/44664807/1116364 我的一个老问题可能有帮助吗?
-
@DanielJour 谢谢。我已经看到你的问题了。我仍然不明白为什么当我默认 ctor 并在单独的文件中定义 Foo 时出现编译错误,但在其他两种情况下却没有。
-
想想 ~Bar 在哪里被实例化:编译器是否可以访问 Foo 在该翻译单元的任何位置的大小? (在 2 个单独的命令中编译 2 个文件可能会更清晰)
标签: c++ compiler-errors c++17 stdvector incomplete-type