0

I want to initialize the sizes of vectors in an array of objects.

Every vector have the same size so...

LIB FILE:

#include <vector>

Class NameClass
{
 public:
  explicit NameClass( unsigned size )
  {
    vectorName.resize( size );
  }

  std::vector <type> vectorName;
};

MAIN FILE:

#include "lib.hpp"

int main( void )
{
  NameClass object( size ); #1

  NameClass object[ number_objects ]( size ); #2
  NameClass object[ number_objects ] = {NameClass(size), NameClass(size), ... }; #3

  return 0;
}

The #1 works, but is not an array, The #2 doesn't, compiler says "conversion from int to non-scalar type 'NameClass' requested" And #3 works, but... it's just absurd initialize every object. and I can't just put a static to size inside the class, because the value change.

So... My research say that I need use std::generate. the question is... Whats is the best way?

Sorry if is easy question how to use std::generate I'm beginner and get troubles to find the optimal solution.

Some people suggest complex solutions but, I keep using my solution

#include "lib.hpp"

int main( void )
{
  unsigned number_objects = something;
  unsigned size = other_thing;
  NameClass object[ number_objects ];

  for( unsigned i = 0; i < number_objects; i++)
    object[i].vectorName.resize( size );

  return 0;
}

I use thins because is really easy to understand, and works. But I'm open to other easy to understand and functional solutions.

link std::generate

4
  • NameClass object[ number_objects ] = {NameClass(size)} should work I think Commented Mar 13, 2017 at 16:32
  • 2
    @Ninetainedo No, this will only init the first one (The rest are default initialized) Commented Mar 13, 2017 at 16:35
  • @Borgleader: Technically, the rest are value-initialized. For vector, the result is the same. Commented Mar 13, 2017 at 16:36
  • 1
    Possible duplicate of stackoverflow.com/questions/4754763/… Commented Mar 13, 2017 at 23:45

4 Answers 4

1

If you are willing to use std::array and C++14, we get:

template<std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
  return [](auto&&f)->decltype(auto) {
    return decltype(f)(f)(std::integral_constant<std::size_t, Is>{}...);
  };
}
template<std::size_t N>
auto index_upto( std::integral_constant<std::size_t, N> ={} ) {
  return index_over( std::make_index_sequence<N>{} );
}

template<std::size_t N, class F,
  class T = std::decay_t<std::result_of_t< F&( std::integral_constant<std::size_t, 0>& )>>,
  class R = std::array<T, N>
>
R make_array( F&& f ) {
  return index_upto<N>()( [&](auto...Is)->R {
    return {{ f( Is )... }};
  } );
}

we pass make_array<count> a lambda. That lambda takes an argument convertible-from a compile-time std::size_t whose value is I, and returns the Ith element of the array.

The result is a std::array of size count.

The lambda could take an auto I to get the compile-time juiciness, or just std::size_t I to get a runtime version of the value.

Most of the above can be translated into C++11, it just gets ugly. And I don't like ugly code.

Live example.

Your code would look like:

int main( void )
{
  unsigned size = 17;
  constexpr std::size_t number_objects = 3;

  auto objects = make_array<number_objects>( [&](std::size_t){ return NameClass(size); } );
}

and objects is now a (std::) array of NameClass of length number_objects, all of size size.

Sign up to request clarification or add additional context in comments.

1 Comment

Is interesting but... In the way that I'm walking, is much more easy just use a for loop and asigne every size of the vector, use few code and is easy to understand. object[i].vectorName.resize( size ); from i = 0, to i < number_objects. I will keep thinking, you solution is c++14 And I have much to learn so... I will study a bit more you amazing c++14 code. maybe is just that I don't understand it.
1

Create a default constructor for your class:

#include <vector>

class NameClass {
 public:
 NameClass() {} // default constructor

 explicit NameClass( unsigned size ){
    vectorName.resize( size );
 }
 std::vector <type> vectorName;
};

In main:

#include "lib.hpp"

int main( void )
{
  unsigned number_objects = something;
  unsigned size = other_thing;
  NameClass object[ number_objects ];

  for( unsigned i = 0; i < number_objects; i++)
    object[i].vectorName.resize( size );

  return 0;
}

The reason example 2 wasn't working is because C++ does not have a syntax for creating an array of objects for which a default constructor is not provided.

In python it would look something like:

[NameClass(size) for _ in range(number_objects)]

I digress.

To do without the default constructor and still create a list of, you can use this (question is why you would want to do this):

#include <iostream>

static constexpr unsigned NUM_OBJECTS = 10;
static constexpr unsigned VEC_SIZE = 30;

int main() {
    NameClass *objects = static_cast<NameClass *>(operator new [](NUM_OBJECTS * sizeof *objects));

    for (unsigned i = 0; i < NUM_OBJECTS; i++) {
        objects[i].vectorName.resize(VEC_SIZE);
    }

    // Required to free memory
    operator delete[](objects);

    return 0;
}

2 Comments

The but the implementation is... How? You put the same main, so I can't understand what's is the difference with the default constructor.
@MoisesRojo, the default constructor is what allows you to declare an array of such items. Without it, the compiler does not have all the necessary information to define an array of NameClass. I posted something further to show how you can do without the default constructor and without any stl containers but only by using some fancy C-like constructs
1

If use vectors is not a problem, actually this works, and is really easy. It's a poem...

class-test.cpp

#include <stdio.h>
#include <algorithm>

#include "class.hpp"

int main( void )
{
  std::vector <NameClass> object(number_objects, NameClass(size));

  printf("%lu\n", object[0].vectorName.size() );

  return 0;
}

class.hpp

#include <vector>
#include <algorithm>

#include <vector>

class NameClass {
 public:
 NameClass() {} // default constructor

 explicit NameClass( unsigned size ){
    vectorName.resize( size );
 }
 std::vector <double> vectorName;
};

And if you want use arrays then just use the default constructor.

clas.hpp

#include <vector>

class NameClass {
 public:
 NameClass(unsigned size) {
 vectorName.resize( size ); 
 } // default constructor

 explicit NameClass( unsigned size ){ // eliminate this
    vectorName.resize( size );
 }
 std::vector <type> vectorName;
};

class-test.cpp

#include <stdio.h>

#include "class.hpp"

int main() {
  NameClass objects[2](4);

  printf("%lu\n", objects[0].vectorName.size());

  return 0;
}

this print a correct output.

Comments

0

You have to initialize every vector, it just how you present it in the code. you can do something this

std::vector<NameClass> classes(number_of_objects);
std::generate(classes.begin(), classes.end(), []{return NameClass(size);});

std::generate will initialize a instance of NameClass for each element of the vector.

2 Comments

g++ class-main.cpp have problems. In file included from class-main.cpp:4:0: class.hpp:7:12: note: candidate: NameClass::NameClass(unsigned int) explicit NameClass( unsigned size ) ^~~~~~~~~ class.hpp:7:12: note: candidate expects 1 argument, 0 provided class.hpp:4:7: note: candidate: NameClass::NameClass(const NameClass&) class NameClass ^~~~~~~~~
If you use std::vector, simply do std::vector<NameClass> classes(number_of_objects, NameClass(size));.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.