array and iterators

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <array>
#include <random>

#define MAX_TILES	100
class TILE;		//	Forward (polymorphic)

class BAG
{
public:
    typedef std::array<TILE *, MAX_TILES>     bag_t;

private:
    int         m_count = 0;
    bag_t       ma_bag;

public:
    void Shuffle();

};

void BAG::Shuffle()
{
    bag_t::const_iterator first = &ma_bag[0];
    bag_t::const_iterator last = &ma_bag[m_count];

    std::shuffle(first, last, std::default_random_engine());
}


I'm having a problem with iterators and std:array.

BAG is a container class that contains a std:array and a count.
I can't seem to find the correct expression for first and last.

The errors I get are:

c:\dev\junk\junk.cpp(23): error C2440: 'initializing': cannot convert from 'TILE **' to 'std::_Array_const_iterator<_Ty,100>'
c:\dev\junk\junk.cpp(23): note: Constructor for class 'std::_Array_const_iterator<_Ty,100>' is declared 'explicit'
c:\dev\junk\junk.cpp(24): error C2440: 'initializing': cannot convert from 'TILE **' to 'std::_Array_const_iterator<_Ty,100>'
c:\dev\junk\junk.cpp(24): note: Constructor for class 'std::_Array_const_iterator<_Ty,100>' is declared 'explicit'

I understand how the compiler arrived at TILE **, but I don't understand what it's looking for on the left side.
I've tried various permutations: ma_bag[0], &(ma_bag[0]), etc.
ma_bag.begin() does work, but I can't use ma_bag.end() as that assumes ma_bag[100], rather than using ma_count for the number of valid elements.

Yes, I know a std::vector would eliminate the need to maintain my own count and I may resort to that.
Last edited on
The error I get is different,
error: no matching function for call to ‘swap(TILE* const&, TILE* const&)’


Which I fixed by doing
1
2
    bag_t::/*const_*/iterator first = &ma_bag[0];
    bag_t::/*const_*/iterator last = &ma_bag[m_count];

Does that help your situation?
Last edited on
Hi Gando
Thanks for the suggestion. Pretty sure I had already tried that.
Removing the const, I get the same error less the const in the type.

1>c:\dev\junk\junk.cpp(23): error C2440: 'initializing': cannot convert from 'TILE **' to 'std::_Array_iterator<_Ty,100>'

Oh, then I can't reproduce the error at all then, sorry.
I'm compiling like
g++ -Wall -c junk.cpp

(edit: And yes, I needed to #include <algorithm>)
Last edited on
This works on the shell:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <array>
#include <random>
#include <algorithm>

#define MAX_TILES	100
class TILE;		//	Forward (polymorphic)

class BAG
{
public:
    typedef std::array<TILE *, MAX_TILES>     bag_t;

private:
    int         m_count = 0;
    bag_t       ma_bag;

public:
    void Shuffle();

};

void BAG::Shuffle()
{
    std::shuffle(ma_bag.begin(), ma_bag.end(), std::default_random_engine());
}

int main()
{
  BAG bag;
  bag.Shuffle();
}

http://cpp.sh/7itv6
@thomas1965

Please see the following in my OP.

I can't use ma_bag.end() as that assumes ma_bag[100], rather than using ma_count for the number of valid elements.
&ma_bag[0] is not an iterator for std::array. It is an address. Also as shuffle() changes the container, the iterator can't be const_iterator.

Also don't use #define for a numeric constant. In C++ use constexpr.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <array>
#include <random>
#include <algorithm>

constexpr int MAX_TILES {100};

class TILE;		//	Forward (polymorphic)

class BAG
{
public:
	typedef std::array<TILE*, MAX_TILES>     bag_t;

private:
	int         m_count = 0;
	bag_t       ma_bag;

public:
	void Shuffle();

};

void BAG::Shuffle()
{
	bag_t::iterator first = ma_bag.begin();
	bag_t::iterator last = ma_bag.end();;

	std::shuffle(first, last, std::default_random_engine());
}


As since C++11, auto is supported. This is easier to write and saves having to know the exact type:

1
2
3
4
5
6
7
void BAG::Shuffle()
{
	const auto first = ma_bag.begin();
	const auto last = ma_bag.end();;

	std::shuffle(first, last, std::default_random_engine());
}


but as first, last are only used once, then as per Thomas1965:

1
2
3
4
void BAG::Shuffle()
{
    std::shuffle(ma_bag.begin(), ma_bag.end(), std::default_random_engine());
}

Last edited on
Sorry I missed that.
Is this an option?
 
std::shuffle(ma_bag.begin(), ma_bag.begin() + m_count, std::default_random_engine());
shuffle requires non const iterators. When the the compiler doesn't like the addresses try this:
1
2
    bag_t::iterator first = ma_bag.begin();
    bag_t::iterator last = first + m_count;
Possibly - depends upon what is wanted. If you only want to shuffle the first m_count items - then yes. If you want to shuffle the whole container - then no.

@seeplus,

The @OP has twice stated what he wants.
Sorry. I saw the .begin() .end() in Thomas1965 first post. Then yes:

 
std::shuffle(ma_bag.begin(), ma_bag.begin() + m_count, std::default_random_engine());

@thomas1965 & coder777,

Thanks. I didn't think about iterator arithmetic. That solved my problem.
Last edited on
Topic archived. No new replies allowed.