#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
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
--
Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
No ads, and there is some C++ stuff! :-) Just going there is good. Linking
to it is even better! Thanks in advance!
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
> 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
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.
It's the type as the object below, declared the same as the typedef but
without the word "typedef":
float float4[4];
An array is a type. Similar to how a pointer can be implicitly converted
into a bool (null = false, non-null = true), an array can be implicitly
converted into a pointer to its first element. The only place an apparent
array really is a pointer is in a function parameter or return value.
Like Jeff Schwab said, avoid arrays an instead use std::vector or
std::tr1::array.
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?
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:
T* get() {
return m_buffer;
}
v.push_back(float4());
v.push_back(float4());
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.
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
That may be. It looks like they're at least thinking along the right
lines, using custom vector and size_t types to wrap arrays:
template <typename T, int N>
struct vector
{
T value_[N];
operator T* () { return value_; }
operator const T* () const { return value_; }
T& operator [](int index) { return value_[index]; }
T operator [](int index) const { return value_[index]; }
};
} // namespace detail
/*!
* \brief size_t class used to interface between C++ and
* OpenCL C calls that require arrays of size_t values, who's
* size is known statically.
*/
template <int N>
struct size_t : public detail::vector< ::size_t, N> { };
> >>> 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).
> > 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.
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.
> > 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.
It isn't legal. It's undefined behavior.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34