 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Andreas Krueger Guest
|
Posted: Sat Oct 18, 2003 12:57 pm Post subject: vector<int> fillVector(int arguments ...) |
|
|
Hi!
I am fed up with
vector<int> iv;
iv.push_back(42); iv.push_back(9); iv.push_back(11); ...
and would rather use a function "fillVector":
vector<int> iv = fillVector(42,9,11);
like in Mathematica(tm): someList={42,9,11};
or even some2dimList={{42},{9,11}};
But there are some difficulties with it.
Perhaps you have good ideas how to solve it?
The sample code is below.
If you don't like templates, just leave out template<class T>
and replace every single "T" by "int"
a) In Visual C++ 6 the sample code works WITHOUT an ending 0:
25 vector<int> intvec=fillVector(800,500,200,300,400);
but in gcc 2.95.2 the last parameter HAS TO BE 0:
25 vector<int> intvec=fillVector(800,500,200,300,400,0);
otherwise the for(; breaks much later.
Moreover, even in Visual C++ 6, the problem occurs with
un-0-terminated lists when I use the vector result as
a parameter for some other function.
(see line 33) - so probably it's just by chance that it
works if I use an intermediate storage vector as in line 25
So: Is there any other way to notice the end (or length)
of a va_list ??? so that the list of parameters doesn't
need to be 0-terminated?
b) It works with "int" but not with "string"
because there doesn't seem to be a "0" in string - or is there?
compiler reports problem in line 15 because of (p==0)
even ( p == (T) 0 ) or a ( p == T(0) ) doesn't help.
any ideas concerning the "0" in string?
c) Any ideas for 2(3)dimensional arrays?
vector<vector intMatrix=fillVector((800,500),(200,300),(400,12));
Please answer not only to the list but also to my email...
Many thanks in advance!
Andreas
sample code:
1 #include <vector>
2 #include <algorithm>
3 #include <iostream>
4 using namespace std;
5 #pragma warning(disable:4786)
6
7 #include <cstdarg>
8 template<class T> vector<T> fillVector(T noZeroes ...){
9 vector<T> theVector;
10 theVector.push_back(noZeroes);
11 va_list ap;
12 va_start(ap, noZeroes);
13 for (; {
14 T p = va_arg(ap, T);
15 if (p==0 ) break;
16 theVector.push_back(p);
17 }
18 va_end(ap);
19 return theVector;
20 } // idea from chapter 7.6 of Stroustrup, 3rd Edition
21
22 void print_tab(int i) { cout<
23 void someFunction(vector
for_each(v.begin(),v.end(),print_tab);
};
24
25 int main (){
26 vector<int> intvec=fillVector(800,500,200,300,400,0);
27 for_each(intvec.begin(),intvec.end(),print_tab);
28 cout<<"n";
29
30 // vector
=fillVector<string > ("Andreas","Test","Schubbidu","");
31 // for_each(stringvec.begin(),stringvec.end(),print_tab);
32
33 someFunction(fillVector(800,500,200,300,400));
34 return 0;
35 }
|
|
| Back to top |
|
 |
Rob Williscroft Guest
|
Posted: Sat Oct 18, 2003 1:36 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
Andreas Krueger wrote in news:59499c44.0310180457.3d188c39
@posting.google.com:
| Quote: | I am fed up with
vector<int> iv;
iv.push_back(42); iv.push_back(9); iv.push_back(11); ...
|
Note the solution I've snipped uses va_args as such it could
*never* portably work with non-POD types (i.e. std::string).
See defenition of append_container<>() below for an alternative
approach.
#include <iostream>
#include <ostream>
#include <iterator>
#include <vector>
#include <algorithm>
int data[3] = { 42, 9, 11 };
void test1()
{
std::vector< int > iv;
std::copy(
data,
data + (sizeof(data)/sizeof(data[0])),
std::back_inserter( iv )
);
std::copy(
iv.begin(),
iv.end(),
std::ostream_iterator< int >( std::cout, ", " )
);
std::cout << std::endl;
}
/* gcc 3.2 was happy with typename C::value_type but it
broke vc7.1 and bcc
*/
template < typename C, typename T, std::size_t N >
void append_container( C &c, T (&data)[ N ] )
{
std::copy( data, data + N, std::back_inserter( c ) );
}
void test2()
{
std::vector< int > iv;
append_container( iv, data );
std::copy(
iv.begin(),
iv.end(),
std::ostream_iterator< int >( std::cout, ", " )
);
std::cout << std::endl;
}
int main()
{
test1();
test2();
}
This works with msvc 7.1, gcc 3.2, and bcc 5.4 good look
with vc 6.0 though.
Rob.
--
http://www.victim-prime.dsl.pipex.com/
|
|
| Back to top |
|
 |
Pete Becker Guest
|
Posted: Sat Oct 18, 2003 1:55 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
Rob Williscroft wrote:
| Quote: |
int data[3] = { 42, 9, 11 };
void test1()
{
std::vector< int > iv;
std::copy(
data,
data + (sizeof(data)/sizeof(data[0])),
std::back_inserter( iv )
);
|
Too much work. vector has a ctor and member functions that take ranges:
std::vector<int> iv(data, data + sizeof(data)/sizeof(data[0]));
iv.assign(data, data + sizeof(data)/sizeof(data[0]));
iv.insert(iv.end(), data, data + sizeof(data)/sizeof(data[0]));
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
|
|
| Back to top |
|
 |
Andreas Krueger Guest
|
Posted: Mon Oct 20, 2003 7:32 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
Hi!
I herewith suggest/demand a better variableLengthType "..."
for the next version of C++.
Thanks to M.Lehn, B.v.Ingen-Schenau and J.Sebastian for all
the suggestions for variable length parameter-functions
vector<T> foo(T data ...).
Some problems remain, though.
I summarize 4 possible solutions
(none of which are really elegant
cause there's NO way of knowing va-length):
a) specialized vector-/matrix-type with overloaded comma-operator
DoubleDenseVector b(3);
b = 1, 2, 3; ([url]http://sourceforge.net/projects/flens/)[/url])
b) first argument (or template argument)
contains length of data
c) using a C-style array as an intermediate container, e.g.:
int tmparr[] = { 42, 9, 11 };
vector<int> iv(tmparr, tmparr + sizeof tmparr / sizeof *tmparr);
d) a sentinel brackets the data.
I like solution (d) but there are still problems with VA_ARG
and STRING (access violation crash) 'cause "va_arg" stems from
C (not C++) as I was told.
So herewith I suggest a better variableLengthType "..."
for the next version of C++.
remaining problems with va_arg:
1)
One seems to need a template specialisation for each C++ type
like string. See code below at // (*)
Here the (const) string data has to be read-in by va_arg as char*
and then (implicitly) converted to string:
parameter = va_arg(ap, char*); // (*)
unfortunately a more compact version like
if (typeid(T)==typeid(string)) parameter = va_arg(ap, char*);
else parameter = va_arg(ap, T);
doesn't compile as soon as one uses fillVector<int>
1a) Why? Other ideas?
1b) Is complete specialisation the only way of solving the string problem?
2)
Why does one need a int- and string-specialisation for
template<class T> void print_tab(T i){ cout<
if one wants to use
template
for_each(v.begin(),v.end(),print_tab<T>); };
??
thanks a lot.
Andreas
#pragma warning(disable:4786)
#include <vector>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#include <cstdarg>
template<class T>
vector<T> fillVector(T sentinelDataSentinel ...){
T parameter, sentinel=sentinelDataSentinel;
vector<T> theVector;
va_list ap; va_start(ap, sentinelDataSentinel);
for (; {
parameter = va_arg(ap, T);
if ( parameter == sentinel ) break;
theVector.push_back(parameter);
}
va_end(ap);
return theVector;
};
template<>
vector<string> fillVector<string>(string sentinelDataSentinel ...){
string parameter, sentinel=sentinelDataSentinel;
vector<string> theVector;
va_list ap; va_start(ap, sentinelDataSentinel);
for (; {
parameter = va_arg(ap, char*); // (*)
if ( parameter == sentinel ) break;
theVector.push_back(parameter);
}
va_end(ap);
return theVector;
};
template<class T> void print_tab(T i){ cout<
template<> void print_tab<string>(string i){ cout<
template<> void print_tab<int> (int i) { cout<
template
for_each(v.begin(),v.end(),print_tab<T>);
};
int main (){
vector<int> intvec=fillVector<int>(0,800,500,200,300,400,0);
coutVector<int>(intvec);
cout<<"n";
vector
=fillVector<string>("stop","Andreas","Test","Schubbidu","stop");
coutVector<string>(stringvec);
return 0;
}
(Andreas Krueger) wrote in message news:<59499c44.0310180458.655b67da (AT) posting (DOT) google.com>...
| Quote: | Hi!
I am fed up with
vector<int> iv;
iv.push_back(42); iv.push_back(9); iv.push_back(11); ...
and would rather use a function "fillVector":
vector<int> iv = fillVector(42,9,11);
like in Mathematica(tm): someList={42,9,11};
or even some2dimList={{42},{9,11}};
But there are some difficulties with it.
Perhaps you have good ideas how to solve it?
The sample code is below.
|
[... see original message 18.10.2003]
|
|
| Back to top |
|
 |
Andreas Müller Guest
|
Posted: Tue Oct 21, 2003 7:30 am Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
Andreas Krueger wrote:
| Quote: | Hi!
I herewith suggest/demand a better variableLengthType "..."
for the next version of C++.
Thanks to M.Lehn, B.v.Ingen-Schenau and J.Sebastian for all
the suggestions for variable length parameter-functions
vector<T> foo(T data ...).
Some problems remain, though.
I summarize 4 possible solutions
(none of which are really elegant
cause there's NO way of knowing va-length):
a) specialized vector-/matrix-type with overloaded comma-operator
DoubleDenseVector b(3);
|
I didn't dig to deep into the thread, but I think that the solution
described this article is doing what you want:
http://www.moderncppdesign.com/publications/inline_containers.html
[snip]
--
To mail me directly, remove the NO*SPAM parts in
NO*SPAMxmen40 (AT) gmx (DOT) netNO*SPAM
|
|
| Back to top |
|
 |
Andreas Krueger Guest
|
Posted: Tue Oct 21, 2003 4:10 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
| Quote: | From: Bjarne Stroustrup [mailto:bs (AT) research (DOT) att.com]
Sent: Tuesday, October 21, 2003 4:44 PM
Subject: Re: vector<int> fillVector(int arguments ...)
Ack.
I think that what you'll get in the next standard is something slightly
different: a notion of a sequence constructor
X(Elem*, Elem*)
that will be used to accept { ... } lists of Elements. That way, we can get
vector<int> v = { 1,2,3,4 };
just as we have
int a[] = { 1,2,3,4 };
Betrifft:Re: vector<int> fillVector(int arguments ...)
Datum:2003-10-20 12:32:54 PST
I herewith suggest/demand a better variableLengthType "..."
for the next version of C++.
|
[...snip...]
[email]usenet (AT) AndreasKrueger (DOT) de[/email] (Andreas Krueger) wrote in message news:<59499c44.0310201132.1cb01993 (AT) posting (DOT) google.com>...
| Quote: | I herewith suggest/demand a better variableLengthType "..."
for the next version of C++.
|
[... snip ....]
see:
http://groups.google.com/groups?selm=59499c44.0310201132.1cb01993%40posting.google.com
|
|
| Back to top |
|
 |
red floyd Guest
|
Posted: Tue Oct 21, 2003 9:01 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
Andreas Krueger wrote:
| Quote: | Hi!
I herewith suggest/demand a better variableLengthType "..."
for the next version of C++.
Thanks to M.Lehn, B.v.Ingen-Schenau and J.Sebastian for all
the suggestions for variable length parameter-functions
vector<T> foo(T data ...).
Some problems remain, though.
I summarize 4 possible solutions
(none of which are really elegant
cause there's NO way of knowing va-length):
a) specialized vector-/matrix-type with overloaded comma-operator
DoubleDenseVector b(3);
b = 1, 2, 3; ([url]http://sourceforge.net/projects/flens/)[/url])
b) first argument (or template argument)
contains length of data
c) using a C-style array as an intermediate container, e.g.:
int tmparr[] = { 42, 9, 11 };
vector<int> iv(tmparr, tmparr + sizeof tmparr / sizeof *tmparr);
d) a sentinel brackets the data.
I like solution (d) but there are still problems with VA_ARG
and STRING (access violation crash) 'cause "va_arg" stems from
C (not C++) as I was told.
So herewith I suggest a better variableLengthType "..."
for the next version of C++.
remaining problems with va_arg:
1)
One seems to need a template specialisation for each C++ type
like string. See code below at // (*)
Here the (const) string data has to be read-in by va_arg as char*
and then (implicitly) converted to string:
parameter = va_arg(ap, char*); // (*)
unfortunately a more compact version like
if (typeid(T)==typeid(string)) parameter = va_arg(ap, char*);
else parameter = va_arg(ap, T);
doesn't compile as soon as one uses fillVector<int
1a) Why? Other ideas?
1b) Is complete specialisation the only way of solving the string problem?
2)
Why does one need a int- and string-specialisation for
template
if one wants to use
template
for_each(v.begin(),v.end(),print_tab<T>); };
??
thanks a lot.
Andreas
[redacted] |
How about:
double d[] = { 1.0, 2.0, 3.0 };
std::vector<double> v(d,d+3);
|
|
| Back to top |
|
 |
red floyd Guest
|
Posted: Tue Oct 21, 2003 9:39 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
red floyd wrote:
| Quote: | Andreas Krueger wrote:
[redacted]
c) using a C-style array as an intermediate container, e.g.:
int tmparr[] = { 42, 9, 11 }; vector<int> iv(tmparr,
tmparr + sizeof tmparr / sizeof *tmparr);
[redacted]
How about:
double d[] = { 1.0, 2.0, 3.0 };
std::vector<double> v(d,d+3);
3
Whoops! Never mind. Missed the OP's item c). |
|
|
| Back to top |
|
 |
Martijn Lievaart Guest
|
Posted: Wed Oct 22, 2003 12:31 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
On Mon, 20 Oct 2003 12:32:53 -0700, Andreas Krueger wrote:
| Quote: | Hi!
I herewith suggest/demand a better variableLengthType "..."
for the next version of C++.
|
How about this (mind you, this hasn't been near a compiler, and probably
is not very efficient, depending on the implementation of
VectorFillerHelpers constructor):
// A real implementation would have up to say 50 parameters.
// A lot of work, but only has to be done once.
// (Hint, write a program to generate this!)
class Sentinel {};
template<class T, class T2, class T3>
class VectorFillerHelper
{
protected:
vector<T> vec;
public:
VectorFillerHelper(T t, T2 t2, T3 t3);
};
template<class T, class T2>
class VectorFillerHelper<T, T2, Sentinel>
{
protected:
vector<T> vec;
public:
VectorFillerHelper(T t, T2 t2);
};
template<class T>
class VectorFillerHelper<T, Sentinel, Sentinel>
{
protected:
vector<T> vec;
public:
VectorFillerHelper(T t);
};
template<class T, class T2=Sentinel, class T3=Sentinel>
class VectorFiller : public VectorFillerHelper<T, T2, T3>
{
public:
operator vector<T>() { return vec; }
VectorFiller(T t, T2 t2, T3 t3) : VectorFillerHelper(t, t2, t3) {}
VectorFiller(T t, T2 t2) : VectorFillerHelper(t, t2) {}
VectorFiller(T t) : VectorFillerHelper(t) {}
};
Note that the frist type passed, must be the type of the vector, e.g.
vector<string> v(VectorFiller(string("1"), "2", "3"));
This can be avoided like this:
replace:
VectorFiller(T t, T2 t2) : VectorFillerHelper(t, t2) {}
with:
template<class U, U2>
VectorFiller(U t, U2 t2) : VectorFillerHelper(t, t2) {}
Also note that using non PAD types quickly runs into undefined behaviour
with varargs, best to avoid varargs completely.
Another aproach could be to have a generic filler, where the type of the
container is passed as the first template parameter. I'm not completely
sure how feasable this is, but I think it can be done.
HTH,
M4
|
|
| Back to top |
|
 |
Jerry Coffin Guest
|
Posted: Thu Oct 23, 2003 7:16 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
In article <59499c44.0310180457.3d188c39 (AT) posting (DOT) google.com>,
[email]usenet (AT) AndreasKrueger (DOT) de[/email] says...
| Quote: | Hi!
I am fed up with
vector<int> iv;
iv.push_back(42); iv.push_back(9); iv.push_back(11); ...
and would rather use a function "fillVector":
vector<int> iv = fillVector(42,9,11);
|
Here's one (perhaps somewhat warped) way of getting something pretty
close:
#include <vector>
template<class T>
class fill_vector {
std::vector<T> data;
public:
fill_vector(T const &val) {
data.push_back(val);
}
fill_vector<T> &operator,(T const &t) {
data.push_back(t);
return *this;
}
operator std::vector<T>() { return data; }
};
template<class T>
fill_vector<T> fillVector(T const &t) {
return fill_vector<T>(t);
}
With this, you can do something like this:
std::vector<int> iv = (fillVector(42), 9, 11);
or:
std::vector<int> iv = (fillVector(42), 9, 11, 17, 21, 34, 99, 22);
or whatever -- you parenthesize the whole list, but call fillVector only
on the first element. After that, the magic of operator overloading
allows it to work with a list of arbitrary length. Note that this uses
the type of the operand to fillVector as the type of the vector that's
created, so if you wanted something like:
std::vector<double> dv = (fillVector(42), 11.0, 2, 17);
it won't work -- but for that situation, you could use:
std::vector<double> dv = (fill_vector<double>(42), 11.0, 2.2, 17);
and the usual arithmetic conversions would force all the numbers to
double.
Overloading the comma operator is generally viewed somewhat dimly
because it doesn't give a sequence point between evaluating the operands
like the built-in comma operator does. IMO, that causes no problem in
this case, because we expect list separator semantics rather than comma
operator semantics.
--
Later,
Jerry.
The universe is a figment of its own imagination.
|
|
| Back to top |
|
 |
Andreas Krueger Guest
|
Posted: Mon Nov 10, 2003 2:33 pm Post subject: Re: vector<int> fillVector(int arguments ...) |
|
|
thought it might be necessary to mention this,
.... just for the protocol.
;-) Andreas
| Quote: | -----Original Message-----
From: Bjarne Stroustrup [mailto:bs (AT) research (DOT) att.com]
Sent: Tuesday, October 21, 2003 7:47 PM
Please be sure to mention that for now that's just a
proposal; not a voted-in feature.
[...snip...]
- Bjarne
Bjarne Stroustrup, http://www.research.att.com/~bs
|
(Andreas Krueger) wrote in message news:<59499c44.0310210810.76bb955a (AT) posting (DOT) google.com>...
| Quote: | From: Bjarne Stroustrup [mailto:bs (AT) research (DOT) att.com]
Ack.
I think that what you'll get in the next standard
is something slightly different:
a notion of a sequence constructor
X(Elem*, Elem*)
that will be used to accept { ... } lists of Elements.
That way, we can get
vector<int> v = { 1,2,3,4 };
just as we have
int a[] = { 1,2,3,4 };
[...snip...]
- Bjarne
Bjarne Stroustrup, http://www.research.att.com/~bs
|
|
|
| Back to top |
|
 |
Powered by phpBB © 2001, 2006 phpBB Group
|