C-Array iterator C++ compliance problem

M

mmacrobert

Hi Everyone,
I wrote 2 functions to make a C-Style array play nice with
std::algorithms as shown:

template <typename T>
T begin(T& t)
{
return t;
}

template <typename T>
T end(T& t)
{
return (t + sizeof(t)/sizeof(t[0]));
}

Usage with a std::algorithm was easy. Thus...

const char* c_style_array[] = {"one","two","three"};

std::for_each(
begin(c_style_array),
end(c_style_array),
...do something);

Life was beautiful,

BUT...

Apparently, my compiler was not standards compliant. On moving to a
more compliant compiler my code broke.

How can I re-write my functions to make my code work again? This
non-compliance is pretty prolific through the codebase.

Thanks,
M


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
V

Victor Bazarov

mmacrobert said:
I wrote 2 functions to make a C-Style array play nice with
std::algorithms as shown:

template <typename T>
T begin(T& t)
{
return t;
}

template <typename T>
T end(T& t)
{
return (t + sizeof(t)/sizeof(t[0]));
}

WHY? "C-Style arrays" decay to pointers, and pointers are iterators,
at least semantically, so they work just fine with algorithms. You
just don't need to use 'begin' or 'end'. Use 'c_style_array' and
'c_style_array + size'.

V
 
H

Hyman Rosen

mmacrobert said:
How can I re-write my functions to make my code work again? This
non-compliance is pretty prolific through the codebase.

template < typename T, unsigned N >
T *begin ( T (&array)[N] ) { return array + 0; }

template < typename T, unsigned N >
T *end ( T (&array)[N] ) { return array + N; }

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
M

mlimber

mmacrobert said:
Hi Everyone,
I wrote 2 functions to make a C-Style array play nice with
std::algorithms as shown:

template <typename T>
T begin(T& t)
{
return t;
}

template <typename T>
T end(T& t)
{
return (t + sizeof(t)/sizeof(t[0]));
}

Usage with a std::algorithm was easy. Thus...

const char* c_style_array[] = {"one","two","three"};

std::for_each(
begin(c_style_array),
end(c_style_array),
...do something);

Life was beautiful,

BUT...

Apparently, my compiler was not standards compliant. On moving to a
more compliant compiler my code broke.

How can I re-write my functions to make my code work again? This
non-compliance is pretty prolific through the codebase.

Thanks,
M

Check out the implementation of boost::array:

http://boost.org/doc/html/array.html

Cheers! --M


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
G

Gianluca Silvestri

mmacrobert said:
Hi Everyone,
I wrote 2 functions to make a C-Style array play nice with
std::algorithms as shown:

template <typename T>
T begin(T& t)
{
return t;
}

template <typename T>
T end(T& t)
{
return (t + sizeof(t)/sizeof(t[0]));
}

Usage with a std::algorithm was easy. Thus...

const char* c_style_array[] = {"one","two","three"};

std::for_each(
begin(c_style_array),
end(c_style_array),
...do something);

Life was beautiful,

BUT...

Apparently, my compiler was not standards compliant. On moving to a
more compliant compiler my code broke.

How can I re-write my functions to make my code work again? This
non-compliance is pretty prolific through the codebase.

Try this:

template <typename T,int N>
T* begin(T (&t)[N])
{
return t;
}

template <typename T, int N>
T* end(T (&t)[N])
{
return (t + N);
}


HTH
Gianluca Silvestri


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
B

benben

template <typename T>
T* begin(T t[])
{
return &t[0];
}

template <typename T>
const T* begin(const T t[])
{
return &t[0];
}

template <typename T, unsigned int SZ>
T* end(T (&t)[SZ])
{
return begin(t) + SZ;
}

template <typename T, unsigned int SZ>
const T* end(const T (&t)[SZ])
{
return begin(t) + SZ;
}

Regards,
Ben



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
T

Thomas Maeder

mmacrobert said:
I wrote 2 functions to make a C-Style array play nice with
std::algorithms as shown:

template <typename T>
T begin(T& t)
{
return t;
}

template <typename T>
T end(T& t)
{
return (t + sizeof(t)/sizeof(t[0]));
}

Usage with a std::algorithm was easy. Thus...

const char* c_style_array[] = {"one","two","three"};

std::for_each(
begin(c_style_array),
end(c_style_array),
...do something);

Life was beautiful,

BUT...

Apparently, my compiler was not standards compliant. On moving to a
more compliant compiler my code broke.

How can I re-write my functions to make my code work again? This
non-compliance is pretty prolific through the codebase.

#include <algorithm>
#include <iterator>
#include <iostream>
#include <ostream>

template <typename T, std::size_t N>
T *begin(T (&t)[N])
{
return t;
}

template <typename T, std::size_t N>
T *end(T (&t)[N])
{
return t+N;
}

int main()
{
int const numbers[] = { 0, 1, 2, 3 };
std::copy(begin(numbers),end(numbers),
std::eek:stream_iterator<int>(std::cout," "));
std::cout << '\n';

char const *c_style_array[] = { "one", "two", "three" };
std::copy(begin(c_style_array),end(c_style_array),
std::eek:stream_iterator<char const *>(std::cout," "));
std::cout << '\n';
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
C

Carlos Moreno

benben said:
template <typename T>
T* begin(T t[])
{
return &t[0];
}

template <typename T>
const T* begin(const T t[])
{
return &t[0];
}

Isn't this entirely redundant? const X will match the
first prototype with T = "const X" and return the right
thing (a pointer to const X). The body of the function
is not doing anything different, so I don't see why the
need for the second version.

Carlos
 
D

Dietmar Kuehl

mmacrobert said:
I wrote 2 functions to make a C-Style array play nice with
std::algorithms as shown:

template <typename T>
T begin(T& t)
{
return t;
}

template <typename T>
T end(T& t)
{
return (t + sizeof(t)/sizeof(t[0]));
}

Actually, I cannot imagine how and why these function should have
ever worked! ... and if they worked, how they could have had the
correct semantics. However, I never had any problems with these
versions:

template <typename T, std::size_t sz>
T* begin(T (&a)[sz])
{
return a + 0;
}

template <typename T, std::size_t sz>
T* end(T (&a)[sz])
{
return a + sz;
}
--
<mailto:[email protected]> <http://www.dietmar-kuehl.de/>
<http://www.eai-systems.com> - Efficient Artificial Intelligence

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
K

kanze

Carlos said:
benben said:
template <typename T>
T* begin(T t[])
{
return &t[0];
}
template <typename T>
const T* begin(const T t[])
{
return &t[0];
}
Isn't this entirely redundant? const X will match the first
prototype with T = "const X" and return the right thing (a
pointer to const X). The body of the function is not doing
anything different, so I don't see why the need for the second
version.

Worse. A const X will result in an ambiguity, since either
function can be used, and is an equally good match.

In practice, I have used compilers which required the const
version, and compilers which didn't accept it, declaring
ambiguity. (And compilers which didn't care, and worked with or
without the const version.) All recent compilers, however, seem
to accept the code without the const versions.

--
James Kanze GABI Software
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


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
B

benben

Isn't this entirely redundant? const X will match the
first prototype with T = "const X" and return the right
thing (a pointer to const X). The body of the function
is not doing anything different, so I don't see why the
need for the second version.

Carlos

You are correct. Its just my habit of providing const versions so i might be
planning to retrofit some idea to any of the versions.

Ben



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
C

Carlos Moreno

kanze said:
template <typename T>
T* begin(T t[])
{
return &t[0];
}
template <typename T>
const T* begin(const T t[])
{
return &t[0];
}

Isn't this entirely redundant? const X will match the first
prototype with T = "const X" and return the right thing (a
pointer to const X). The body of the function is not doing
anything different, so I don't see why the need for the second
version.


Worse. A const X will result in an ambiguity, since either
function can be used, and is an equally good match.

Huh? What about partial specialization rules? Something
that matches "const T" matches also T, but something that
matches T does not necessarily match const T -- if const T
is a "most specialized" match, then it should be chosen.

Am I missing something?

Carlos
 
J

James Kanze

Carlos said:
kanze wrote:
template <typename T>
T* begin(T t[])
{
return &t[0];
}
template <typename T>
const T* begin(const T t[])
{
return &t[0];
}
Isn't this entirely redundant? const X will match the first
prototype with T = "const X" and return the right thing (a
pointer to const X). The body of the function is not doing
anything different, so I don't see why the need for the
second version.
Worse. A const X will result in an ambiguity, since either
function can be used, and is an equally good match.
Huh? What about partial specialization rules? Something that
matches "const T" matches also T, but something that matches T
does not necessarily match const T -- if const T is a "most
specialized" match, then it should be chosen.
Am I missing something?

Or I am. I thought that partial specialization only applied to
classes.

I did think that there was some sort of ordering on
specializations over functions, that might apply here, but I
didn't find it immediately, and it didn't seem worth searching
further. The fact is that some compilers I have used did
declare it ambiguous. Which means that regardless of what the
standard actually says...

Of course, some compilers also required it. Which made life
pretty difficult for a while. All I can say is that I currently
don't use the extra declarations, and that the code passes the
compilers I am currently using (Sun CC 5.1, and some later
version, and g++ 3.4.? up).

--
James Kanze mailto: (e-mail address removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

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

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,197
Latest member
ScottChare

Latest Threads

Top