I have a header file like the below -
// abc.hpp
#include <vector>
#include <string>
namespace A
{
namespace B
{
struct abc
{
std::string _type;
};
using abc_vector = std::vector<abc>;
}
}
I am using forward declaration in another header file.
// 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);
};
}
}
What really confuses me is that my code compiles and works.
How is the vector allowed to be declared with incomplete type? I think that it shouldn't be able to decide the size of abc.
using abc_vector = std::vector<abc>;
The below is the code I used to test my header files. Strange enough, that it compiles and works all fine.
#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;
}
The code line
using abc_vector = std::vector<abc>;
only introduces a type alias for std::vector<abc>
. That doesn't require, by any means, the size of abc
since no object of type abc
is allocated at all. Only a new type is declared.
B::abc_vector d;
Indeed needs the definition of abc
. Nevertheless it works because at this point abc
already has been defined because the header file abc.hpp
has been included.
You are referring to this answer, where
std::vector<B> v;
is "done." This is not the same as what you did. You just introduced a type alias. std::vector<B> v;
actually defines a variable. Therefore the definition of B
is mandatory.
Note that
using abc_vector = std::vector<abc>;
is equivalent to
typedef std::vector<abc> abc_vector;
Maybe this makes it a bit clearer why the size of abc
isn't necessary to know at this time point in compilation.
This is an interesting topic (at least to me) and applies to other std containers.
Originally the standard made it undefined behaviour to instantiate a container of an incomplete type. However implementations did not disallow it. This was in all likelihood not deliberate, but merely a side-effect of the fact that elements in (for example the vector) are stored in a memory location that is referenced by a pointer.
Thus the size of an element does not need to be known until an element is actually required - during the instantiation of a member function of the vector.
Here is a starting point for research if you'd like to explore further:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4056.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With