typedef float float4[4]; std::vector<float4>; does not compile, why?

B

Brian Cole

The following code will not compile in gcc 4.3.2 on Ubuntu 8.10

#include <vector>

typedef float float4[4];

int main()
{
std::vector<float4> vals;
}

I get the following compilation error:
/usr/include/c++/4.3/bits/stl_construct.h: In function ‘void
std::_Destroy(_Tp*) [with _Tp = float [4]]’:
/usr/include/c++/4.3/bits/stl_construct.h:103: instantiated from
‘void
std::_Destroy(_ForwardIterator, _ForwardIterator) [with
_ForwardIterator =
float (*)[4]]’
/usr/include/c++/4.3/bits/stl_construct.h:128: instantiated from
‘void
std::_Destroy(_ForwardIterator, _ForwardIterator,
std::allocator<_T2>&) [with
_ForwardIterator = float (*)[4], _Tp = float [4]]’
/usr/include/c++/4.3/bits/stl_vector.h:300: instantiated from
‘std::vector<_Tp, _Alloc>::~vector() [with _Tp = float [4], _Alloc =
std::allocator<float [4]>]’
test_float4.cpp:7: instantiated from here
/usr/include/c++/4.3/bits/stl_construct.h:88: error: request for
member ‘~float
[4]’ in ‘* __pointer’, which is of non-class type ‘float [4]’

The code does compile in gcc 3.4 and gcc 4.1. So I'm guessing this is
because of some "enlightened" understanding of the C++ standard?
Please enlighten me.

Thanks
-Brian
 
A

Alf P. Steinbach

* Brian Cole:
The following code will not compile in gcc 4.3.2 on Ubuntu 8.10

#include <vector>

typedef float float4[4];

int main()
{
std::vector<float4> vals;
}

I get the following compilation error:
/usr/include/c++/4.3/bits/stl_construct.h: In function ‘void
std::_Destroy(_Tp*) [with _Tp = float [4]]’:
/usr/include/c++/4.3/bits/stl_construct.h:103: instantiated from
‘void
std::_Destroy(_ForwardIterator, _ForwardIterator) [with
_ForwardIterator =
float (*)[4]]’
/usr/include/c++/4.3/bits/stl_construct.h:128: instantiated from
‘void
std::_Destroy(_ForwardIterator, _ForwardIterator,
std::allocator<_T2>&) [with
_ForwardIterator = float (*)[4], _Tp = float [4]]’
/usr/include/c++/4.3/bits/stl_vector.h:300: instantiated from
‘std::vector<_Tp, _Alloc>::~vector() [with _Tp = float [4], _Alloc =
std::allocator<float [4]>]’
test_float4.cpp:7: instantiated from here
/usr/include/c++/4.3/bits/stl_construct.h:88: error: request for
member ‘~float
[4]’ in ‘* __pointer’, which is of non-class type ‘float [4]’

The code does compile in gcc 3.4 and gcc 4.1. So I'm guessing this is
because of some "enlightened" understanding of the C++ standard?
Please enlighten me.

The element type of a standard container must be copyable.

A raw array isn't.

Curiously, the code above compiles with Comeau Online, which appears to be a bug
in Comeau (considering that it aims to catch most errors).

Try this:


<code>
#include <vector>

typedef float float4[4];

int main()
{
std::vector<float4> vals;
float4 v = {};
vals.push_back( v );
}
</code>

It should not compile.


Cheers & hth.,

- Alf
 
S

SG

The following code will not compile in gcc 4.3.2 on Ubuntu 8.10

#include <vector>

typedef float float4[4];

int main()
{
  std::vector<float4> vals;
}

As Alf said, float4 doesn't satisfy the vector templates' requirements
as a value type.

If your C++ implementation ships with the TR1 library extension or you
can install some TR1 implementation and/or Boost you could solve this
problem via:

typedef std::tr1::array<float,4> float4;

Cheers!
SG
 
B

Brian Cole

The following code will not compile in gcc 4.3.2 on Ubuntu 8.10
#include <vector>
typedef float float4[4];
int main()
{
  std::vector<float4> vals;
}

As Alf said, float4 doesn't satisfy the vector templates' requirements
as a value type.

If your C++ implementation ships with the TR1 library extension or you
can install some TR1 implementation and/or Boost you could solve this
problem via:

  typedef std::tr1::array<float,4> float4;

Cheers!
SG

Apparently GCC considers this a bug (http://gcc.gnu.org/bugzilla/
show_bug.cgi?id=40192). So now I'm doubly confused.

I'm not a language lawyer, is "float4" a pointer to an array of 4
floats? Or is it an array of 4 floats? Basically if we define float4_t
as "struct float4_t { float x,y,z,w; };" is std::vector<float4>
equivalent to std::vector<float4_t> or std::vector<float4_t *>.

Thanks,
Brian
 
B

Brian Cole

Brian said:
The following code will not compile in gcc 4.3.2 on Ubuntu 8.10
#include <vector>
typedef float float4[4];
int main()
{
  std::vector<float4> vals;
}
As Alf said, float4 doesn't satisfy the vector templates' requirements
as a value type.
If your C++ implementation ships with the TR1 library extension or you
can install some TR1 implementation and/or Boost you could solve this
problem via:
  typedef std::tr1::array<float,4> float4;
Apparently GCC considers this a bug (http://gcc.gnu.org/bugzilla/
show_bug.cgi?id=40192). So now I'm doubly confused.

It wasn't a bug.  They should not have "fixed" it.
I'm not a language lawyer, is "float4" a pointer to an array of 4
floats? Or is it an array of 4 floats?

It's an array (in your original post).  C++ raw arrays decay to
pointers, but that's not something you should need to worry about unless
you're manually laying out memory.  You almost never should need a raw
array.  Forget about raw arrays.
Basically if we define float4_t
as "struct float4_t { float x,y,z,w; };" is std::vector<float4>
equivalent to std::vector<float4_t> or std::vector<float4_t *>.

Neither.  std::vector<float[4]> shouldn't even be legal.

FYI, the reason this arose is because I am toying with the OpenCL
libraries which defines the type: http://www.khronos.org/registry/cl/api/1.0/cl_platform.h

If it truly is illegal I think OpenCL should change the definition to
a struct to be friendlier with C++.

-Brian
 
C

Chris M. Thomasson

Brian Cole said:
The following code will not compile in gcc 4.3.2 on Ubuntu 8.10

#include <vector>

typedef float float4[4];

int main()
{
std::vector<float4> vals;
}

I get the following compilation error:


Try something like this:
_____________________________________________________________________
#include <cstdio>
#include <cstddef>
#include <cassert>
#include <vector>


template<typename T, std::size_t T_size>
class array {
T m_buffer[T_size];

public:
enum constant {
SIZE = T_size
};


T& operator [] (std::size_t size) {
assert(size < T_size);
return m_buffer[size];
}


T const& operator [] (std::size_t size) const {
assert(size < T_size);
return m_buffer[size];
}


T* get() {
return m_buffer;
}


T const* get() const {
return m_buffer;
}
};


typedef array<unsigned, 4> float4;


int main() {
std::vector<float4> v;

v.push_back(float4());
v.push_back(float4());

v[0][0] = 1;
v[0][1] = 2;
v[0][2] = 3;
v[0][3] = 4;

v[1][0] = 5;
v[1][1] = 6;
v[1][2] = 7;
v[1][3] = 8;

std::size_t c1;
std::vector<float4>::iterator i;

for (i = v.begin(), c1 = 0; i != v.end(); ++i, ++c1) {
for (std::size_t c2 = 0; c2 < float4::SIZE; ++c2) {
std::printf("v[%u][%u] == %u\n", c1, c2, v[c1][c2]);
}
}

return 0;
}
_____________________________________________________________________



Does that work for you?
 
C

Chris M. Thomasson

Chris M. Thomasson said:
Brian Cole said:
The following code will not compile in gcc 4.3.2 on Ubuntu 8.10

#include <vector>

typedef float float4[4];

int main()
{
std::vector<float4> vals;
}

I get the following compilation error:


Try something like this:
_____________________________________________________________________
[...]> std::size_t c1;
std::vector<float4>::iterator i;

for (i = v.begin(), c1 = 0; i != v.end(); ++i, ++c1) {
for (std::size_t c2 = 0; c2 < float4::SIZE; ++c2) {
std::printf("v[%u][%u] == %u\n", c1, c2, v[c1][c2]);
}
}

return 0;
}
_____________________________________________________________________

[...]




Ummm.... I don't know why I did the iteration that way. Perhaps I should
actually use the damn iterator object `i'!!! Here, let me try again:
_____________________________________________________________________
#include <cstdio>
#include <cstddef>
#include <cassert>
#include <vector>


template<typename T, std::size_t T_size>
class array {
T m_buffer[T_size];

public:
enum constant {
SIZE = T_size
};


T& operator [] (std::size_t size) {
assert(size < T_size);
return m_buffer[size];
}


T const& operator [] (std::size_t size) const {
assert(size < T_size);
return m_buffer[size];
}


T* get() {
return m_buffer;
}


T const* get() const {
return m_buffer;
}
};


typedef array<unsigned, 4> float4;


int main() {
std::vector<float4> v;

v.push_back(float4());
v.push_back(float4());

v[0][0] = 1;
v[0][1] = 2;
v[0][2] = 3;
v[0][3] = 4;

v[1][0] = 5;
v[1][1] = 6;
v[1][2] = 7;
v[1][3] = 8;

std::size_t c1;
std::vector<float4>::const_iterator i;

for (i = v.begin(), c1 = 0; i != v.end(); ++i, ++c1) {
for (std::size_t c2 = 0; c2 < float4::SIZE; ++c2) {
std::printf("v[%u][%u] == %u\n", c1, c2, (*i)[c2]);
}
}

return 0;
}
_____________________________________________________________________



There... That's better. I mean, the first posted program works, but its
retarded! Sorry about that.
 
B

Brian Cole

Brian said:
Brian Cole wrote:
The following code will not compile in gcc 4.3.2 on Ubuntu 8.10
#include <vector>
typedef float float4[4];
int main()
{
  std::vector<float4> vals;
}
As Alf said, float4 doesn't satisfy the vector templates' requirements
as a value type.
If your C++ implementation ships with the TR1 library extension or you
can install some TR1 implementation and/or Boost you could solve this
problem via:
  typedef std::tr1::array<float,4> float4;
Apparently GCC considers this a bug (http://gcc.gnu.org/bugzilla/
show_bug.cgi?id=40192). So now I'm doubly confused.
It wasn't a bug.  They should not have "fixed" it.
I'm not a language lawyer, is "float4" a pointer to an array of 4
floats? Or is it an array of 4 floats?
It's an array (in your original post).  C++ raw arrays decay to
pointers, but that's not something you should need to worry about unless
you're manually laying out memory.  You almost never should need a raw
array.  Forget about raw arrays.
Basically if we define float4_t
as "struct float4_t { float x,y,z,w; };" is std::vector<float4>
equivalent to std::vector<float4_t> or std::vector<float4_t *>.
Neither.  std::vector<float[4]> shouldn't even be legal.
FYI, the reason this arose is because I am toying with the OpenCL
libraries which defines the type:http://www.khronos.org/registry/cl/api/1.0/cl_platform.h
If it truly is illegal I think OpenCL should change the definition to
a struct to be friendlier with C++.

Khronos probably should have defined:

        struct float4 { float values[4]; }

In C, though, it is common to use arrays directly as containers, for
historical reasons, and OpenCL is apparently based on C99.  OpenCL is
full of other C-related nastiness, too; for example, it defines names
like float4 directly in the global namespace.  Namespace pollution is a
real problem in large programs.

One easy way around the vector<float4> problem is to wrap float4 in your
own class.

There is a C++ wrapper layer being developed on top of OpenCL:
http://www.khronos.org/registry/cl/api/1.0/cl.hpp It will be part of
the 1.1 standard.

This is perhaps a nastiness that should be dealt with there now that I
am thoroughly convinced that cl_float4 does not play nice with C++.

-Brian
 
J

James Kanze

Brian said:
The following code will not compile in gcc 4.3.2 on Ubuntu 8.10
#include <vector>
typedef float float4[4];
int main()
{
std::vector<float4> vals;
}
As Alf said, float4 doesn't satisfy the vector templates'
requirements as a value type.
If your C++ implementation ships with the TR1 library
extension or you can install some TR1 implementation and/or
Boost you could solve this problem via:
typedef std::tr1::array<float,4> float4;
Apparently GCC considers this a bug (http://gcc.gnu.org/bugzilla/
show_bug.cgi?id=40192). So now I'm doubly confused.
It wasn't a bug. They should not have "fixed" it.

In C++03, it's a quality of implementation issue. The standard
says it's undefined behavior. And while the instantiation of
the vector works (I don't know why) in both g++ and VC++, you
can't do anything with it---none of the member functions work.
From a QoI point of view, the error should be detected by the
compiler if possible.

In C++0x, IIUC, it will require a diagnostic (unless arrays are
somehow MoveConstructable---I'm not too sure about the
implications of rvalue references with regards to arrays).
It's an array (in your original post). C++ raw arrays decay
to pointers, but that's not something you should need to worry
about unless you're manually laying out memory. You almost
never should need a raw array. Forget about raw arrays.

Yes. In this context, as far as I can tell, the array doesn't
decay into a pointer. If it did, the template instantation
would be legal---but would be the exact equivalent of
std::vector< float* >.

About the only use for raw arrays I know is in order to obtain
static initialization and automatic calculation of the size.
Neither. std::vector<float[4]> shouldn't even be legal.

It isn't legal. It's undefined behavior.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top