How to Declare a Member Vector of the Same Class

How can I declare a member vector of the same class?

This paper was adopted into C++17 which allows incomplete types to be used in certain STL containers. Prior to that, it was Undefined Behavior. To quote from the paper:

Based on the discussion on the Issaquah meeting, we achieved the
consensus to proceed* with the approach – “Containers of Incomplete
Types”, but limit the scope to std::vector, std::list, and
std::forward_list, as the first step.

And as for the changes in the standard (emphasis mine):

An incomplete type T may be used when instantiating vector if the
allocator satisfies the allocator-completeness-requirements
(17.6.3.5.1). T shall be complete before any member of the resulting
specialization of vector is referenced.

So, there you have it, if you leave the default std::allocator<T> in place when instantiating the std::vector<T, Allocator>, then it will always work with an incomplete type T according to the paper; otherwise, it depends on your Allocator being instantiable with an incomplete type T.


A is an incomplete type, right? If there was a vector of A*s I would understand. But here I don't understand how it works. It seems to be a recursive definition.

There is no recursion there. In an extremely simplified form, it's similar to:

class A{
A* subAs;
};

Technically, apart from size, capacity and possibly allocator, std::vector only needs to hold a pointer to a dynamic array of A it manages via its allocator. (And the size of a pointer is known at compile time.)

So, an implementation may look like this:

namespace std{

template<typename T, typename Allocator = std::allocator<T>>
class vector{

....

std::size_t m_capacity;
std::size_t m_size;
Allocator m_allocator;
T* m_data;
};

}

How to pass a vector from a member function to another in the same class?

you have two solutions you can declare your vector as a member variable

#pragma once
#include <string>
#include <iostream>
#include <vector>

class Game
{
std::vector<std::string> _l;

public:
Game();
~Game();

void draw();
};

or you can also just directly give as parameter to your function

but the member variable declaration seems to be the best solution

C++ how to declare a vector of objects as a member of a class

Item must be defined before its usage as a template argument.

Technically, you may be able to get away with a forward declaration in specific contexts, but to save you time and frustration with learning the exact rules, it is easier to just make sure you have defined it first.

In general, the order of declarations are important. If you use a type in the declaration of another type, the used type must already be defined. Exceptions to this rule involve usage by pointer and reference which only require forward declaration.

Vector as a class member

You most certainly want to use std::vector<int> myVector. No need to initialize it, as it gets automatically initialized in the constructor of your class and deallocated when your class is destroyed.

create a vector of instances of a class in c++

This:

vector <Student> ver[N];

Creates an array of N elements. Each element is vector<Student>. This is not you want. You were probably trying to create a vector of N elements. The syntax for this is:

vector <Student> ver(N);

But you can't use this because your class does not have a default constructor. So your next alternative is to initializae all the objects with the same element.

vector <Student> ver(N, Student(0));

You also tried to create an array of students like this:

Student ver[N];

This will not work. Because it tries to initialize every element in the array with the default constructor. But your class does not have a default constructor. So this will not work. But this is why your original code did work:

Student ver_list[2] = {7, 9};  // Here you are using the constructor for your object.
// It uses the normal constructor you provided not the default one.

The other issues is that you can not run code outside a function(method).

So this will not work:

for(unsigned int i = 0; i < N; ++i )
ver[i].set_id(i);

In C++11 you can initialize a vector the same way as an array:

vector<Student>  ver = { 0, 1, 2, 3, 4, 5};

If you don't have C++11 or initialization is more complex. Then you need to write a wrapper.

class VecWrapper
{
public:
std::vector<Student> ver;
VecWrapper()
{
ver.reserve(N);
for(unsigned int i = 0; i < N; ++i )
ver.push_back(Student(i));
}
};

Now You can place this in global scope and it will auto init.

 VecWrapper   myData;  // myData.vec  initializaed before main entered.

int main()
{}

Full solution:

Option 2:

#include<iostream>
#include<vector>
using namespace std;

const unsigned int N = 5;

// The following is not correct
// This creates an arrya of `N` elements each element is `vector <Student>`
//
// vector <Student> ver[N]; // Create vector with N elements
//

// The following lines are not allowed.
// All code has to be inside a function.
//
// for(unsigned int i = 0; i < N; ++i )
// ver[i].set_id(i);

// What you want is:
// I use the following because it is unclear if you have C++11 or not.
class VecWrapper
{
public:
std::vector<Student> vec;
VecWrapper()
{
vec.reserve(N);
for(unsigned int i = 0; i < N; ++i )
vec.push_back(Student(i));
}
};
VecWrapper myData; // myData.vec
int main()
{

cout<< "Hello, This is a code to learn classes"<< endl;

cout<< myData.vec[1].get_id() << endl;

return 0;
}

How to create a vector of class objects in C++?

vector<Site> myStack();

This is actually a function declaration. The function is called myStack and it returns a vector<Site>. What you actually want is:

vector<Site> myStack;

The type of neighbours at the moment will store copies of the objects, not references. If you really want to store references, I recommend using a std::reference_wrapper (rather than using pointers):

vector<reference_wrapper<Site>> neighbors;

declare a template vector member in a class without template the class?

There are a few different ways to shear this beast. It mostly depends on how you want to access this vector and how you determine its exact type at runtime.

std::variant

A variant can store a set of predetermined types. It's effective but also cumbersome if you have many different types because you have to funnel every access through some type checking.

class SomeClass {
public:
using variant_type = std::variant<
std::vector<int>, std::vector<double> >;
int _someField;
variant_type _fieldValues;

void print(std::ostream& stream) const
{
switch(_fieldValues.index()) {
case 0:
for(int i: std::get<0>(_fieldValues))
stream << i << ' ';
break;
case 1:
for(double i: std::get<1>(_fieldValues))
stream << i << ' ';
break;
default: break;
}
}
};

std::any

Any can hold literally any type. Improves extendability but makes working with the values hard.

class SomeClass {
public:
int _someField;
std::any _fieldValues;

void print(std::ostream& stream) const
{
if(_fieldValues.type() == typeid(std::vector<int>))
for(int i: std::any_cast<std::vector<int>>(_fieldValues))
stream << i << ' ';
else if(_fieldValues.type() == typeid(std::vector<double>))
for(double i: std::any_cast<std::vector<double>>(_fieldValues))
stream << i << ' ';
else
throw std::runtime_error("Not implemented");
}
};

Subclassing

The most elegant way (IMHO) is to use a templated subclass. Something like this:

class SomeClass {
public:
int _someField;
virtual ~SomeClass() = default;
virtual void print(std::ostream& stream) const = 0;
};
template<class T>
SomeClassT: public SomeClass
{
std::vector<T> _fieldValues;
public:
virtual void print(std::ostream& stream) const
{
for(const T& i: _fieldValues)
stream << i << ' ';
}
};

Or if you don't want to expose that part, make it a private member.

class SomeClassHelper {
public:
virtual ~SomeClassHelper() = default;
virtual void print(std::ostream& stream) const = 0;
};

template<class T>
SomeClassHelperT: public SomeClassHelper
{
std::vector<T> _fieldValues;
public:
virtual void print(std::ostream& stream) const
{
for(const T& i: _fieldValues)
stream << i << ' ';
}
};
class SomeClass {
public:
int _someField;
private:
std::unique_ptr<SomeClassHelper> helper;
public:
void print(std::ostream& stream) const
{ return helper->print(stream); }
};

Create vector of member variables from vector of class pointers

What you've got is the best you can do, if you need another vector. It can be made a bit more C++-like with std::transform and an insert iterator, but it's hard to see how that code would be any clearer than your simple loop.

You cannot cast one vector type to another, even if their respective element types are related.

You can try to obviate the need for it by iterating over your existing container using filtering functions that stop you having to write ->member everywhere, but that really depends on what you're trying to do (which we don't know).



Related Topics



Leave a reply



Submit