std :: vector的声明适用于前向声明的类..?

时间:2015-10-19 11:43:19

标签: c++

我有一个如下所示的头文件 -

// abc.hpp
#include <vector>
#include <string>

namespace A 
{
    namespace B 
    {   
        struct abc 
        {   
            std::string _type;
        };  

        using abc_vector = std::vector<abc>;
    }   

}

我在另一个头文件中使用前向声明。

// con.hpp
#include <vector>

namespace A 
{
    namespace B 
    {   
        struct abc; // Forward Declaration
        using abc_vector = std::vector<abc>;
    }   

    namespace C
    {   
        class N
        {   
            public:
                B::abc_vector foo(std::string type);
        };  
    }   
}

让我感到困惑的是我的代码编译和工作。

如何使用不完整类型声明向量...? 我认为它不应该能够决定 的大小

using abc_vector = std::vector<abc>;

以下是我用来测试头文件的代码。 奇怪的是,它编译并且工作得很好。

#include "con.hpp"
#include "abc.hpp"

#include <iostream>

namespace A
{
    namespace C
    {   
        B::abc_vector N::foo(std::string type)
        {   
            B::abc a;
            a._type = type;

            B::abc_vector d;
            d.push_back(a);
            return d;
        }   
    }   
}

int main()
{
    A::C::N n;
    auto container = n.foo("test");

    for (const auto& i : container)
          std::cout << i._type << ' ';

    return 0;
}

3 个答案:

答案 0 :(得分:3)

代码行

using abc_vector = std::vector<abc>;

std::vector<abc>引入了类型别名。无论如何,这都不需要abc的大小,因为根本没有分配abc类型的对象。只声明了一种新类型。

B::abc_vector d;

确实需要abc的定义。不过它可行,因为此时abc已经定义,因为已包含头文件abc.hpp

您指的是this answer,其中

std::vector<B> v;

已“完成”。这跟你的做法不一样。您刚刚介绍了一个类型别名。 std::vector<B> v;实际上定义了变量。因此,B的定义是强制性的。

请注意

using abc_vector = std::vector<abc>;

相当于

typedef std::vector<abc> abc_vector;

也许这使得为什么在编译的这个时间点不需要知道abc的大小更清楚一点。

答案 1 :(得分:2)

这是一个有趣的话题(至少对我而言)并适用于其他std容器。

最初,标准使得实例化不完整类型的容器成为未定义的行为。但是实现并没有禁止它。这很可能不是故意的,而只是因为(例如向量)中的元素存储在由指针引用的内存位置这一事实的副作用。

因此,在实际需要一个元素之前,不需要知道元素的大小 - 在向量的成员函数的实例化期间。

如果您想进一步探索,这是研究的起点:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4056.html

答案 2 :(得分:2)

有一个有趣的观察结果。 GCC5.2CLANG3.6都编译以下代码。

struct A;

std::vector<A> my_func(); //Definition of my_func is in some CPP file

但是为

抛出错误
struct A;

std::vector<A> v;

对此的推理是,矢量的大小不会因为它所持有的不同类型而发生变化。请参阅以下代码段。

struct B{int i; int j;};
struct C{int a,b,c;};

std::vector<B> pp;
std::vector<C> qq;

int main()
{
  std::cout<<sizeof(pp)<<'\n';
  std::cout<<sizeof(qq)<<'\n';
}

输出

24

24

但对于std::vector<A> v,它也必须提供Allocator<A>()。而分配器需要struct A的成员,如构造函数,复制构造函数,析构函数等。 此处需要注意的一件重要事情是pointer arithmetic for incomplete type is not allowed.

如果您看到CLANG抛出的错误,它显然会说同样的错误。

In file included from /tmp/gcc-explorer-compiler115920-68-1xsb8x7/example.cpp:2:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/vector:64:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_vector.h:161:9: error: arithmetic on a pointer to an incomplete type 'A'
- this->_M_impl._M_start); }
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_vector.h:253:7: note: in instantiation of member function 'std::_Vector_base<A, std::allocator<A> >::~_Vector_base' requested here
vector()
^

其他一切都很直接。

以下是typedef,因此编译器需要了解大小。

using abc_vector = std::vector<abc>;

因此,讨论的代码结构很适合继续。