Сначала немного фона. Как сказано в стандарте C ++ 17:
[vector.overview] / 3 При создании экземпляра вектора может использоваться неполный тип T, если распределитель удовлетворяет требованиям полноты распределителя 17.6.3.5.1. T должен быть завершен до того, как будет получен доступ к любому члену результирующей специализации вектора.
Я пробовал 3 сценария ios в этом репо (код скопирован внизу):
- Класс, содержащий неполный векторный тип, объявлен (ctor / dtor по умолчанию) и определен в том же заголовочном файле << Compilation Succeeds <ul>
- компиляция с включенным ah:
clang++ test.cpp --std=c++17
- Класс, содержащий неполный векторный тип, объявлен (ctor / dtor по умолчанию) и определен в заголовочных и исходных файлах << <strong>Сбой компиляции
- компиляция с включенным bh:
clang++ test.cpp b.cpp --std=c++17
- Класс, содержащий неполный векторный тип, объявлен и определен в заголовочных и исходных файлах (явно определены ctor / dtor) << Успех компиляции <ul>
- компиляция с включенным bh:
clang++ test.cpp c.cpp --std=c++17
Мой вопрос: почему компиляция заканчивается во втором случае, а не в первом или третьем? Если, как гласит стандарт, на элемент std :: vector ссылаются, то почему на него не ссылаются только в случае заголовка? И что это за член? Можно ли как-нибудь компилировать второй случай, не касаясь ключевого слова по умолчанию или предварительного объявления?
PS Я пробовал использовать 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.