Ошибка компиляции для неполного векторного типа (C ++ 17) - PullRequest
0 голосов
/ 06 января 2020

Сначала немного фона. Как сказано в стандарте C ++ 17:

[vector.overview] / 3 При создании экземпляра вектора может использоваться неполный тип T, если распределитель удовлетворяет требованиям полноты распределителя 17.6.3.5.1. T должен быть завершен до того, как будет получен доступ к любому члену результирующей специализации вектора.

Я пробовал 3 сценария ios в этом репо (код скопирован внизу):

  1. Класс, содержащий неполный векторный тип, объявлен (ctor / dtor по умолчанию) и определен в том же заголовочном файле << Compilation Succeeds <ul>
  2. компиляция с включенным ah: clang++ test.cpp --std=c++17
  3. Класс, содержащий неполный векторный тип, объявлен (ctor / dtor по умолчанию) и определен в заголовочных и исходных файлах << <strong>Сбой компиляции
    • компиляция с включенным bh: clang++ test.cpp b.cpp --std=c++17
  4. Класс, содержащий неполный векторный тип, объявлен и определен в заголовочных и исходных файлах (явно определены ctor / dtor) << Успех компиляции <ul>
  5. компиляция с включенным 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.

Ответы [ 2 ]

0 голосов
/ 25 марта 2020

Сбой, потому что у вас есть конструктор и деструктор по умолчанию, это означает, что реализация находится в каждой единице компиляции, как вы написали бы.

struct Bar
{
    Bar() {}
    ~Bar() {}
    std::vector<Foo> foos;
};

И тогда компилятору нужно знать размер Foo и хочет вызвать его деструктор.

Но если вы привносите реализацию функций в .cpp и имеете только объявление в заголовке, вы можете спокойно скомпилировать main.cpp, потому что все, что нужно компилятору чтобы знать, есть ли.

Вы также можете (и я бы порекомендовал) по умолчанию функции в c.cpp:

#include "c.h"

struct Foo
{
};

Bar::Bar() = default;
Bar::~Bar() = default;
0 голосов
/ 06 января 2020

включая чч не сработает. Где-то внутри шаблона std :: vector будет строка, которая выделяет память для NUM * sizeof(Foo). Если вы похороните определение Foo в исходном файле, то размер Foo будет неизвестен, и компиляция не удастся.

...