Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > template with stdarg: enum problem

Reply
Thread Tools

template with stdarg: enum problem

 
 
Klaus Schneider
Guest
Posts: n/a
 
      10-12-2005
Hi all!

I'm having trouble with a template function with variable arguments when I
parse an enum type as variable argument. Example:

template <class T>
bool test(int num, ...)
{
va_list ap;
int ind;
bool allequal = true;

va_start(ap, num);
T lastentry((T)va_arg(ap, T));
for(ind=0; ind<num; ind++) {
T entry((T)va_arg(ap, T));
/* do something with T */
if (lastentry != entry)
allequal = false;
lastentry = entry;
}
va_end(ap);

return allequal;
}

Now, if I call this template using an enum, as
typedef enum { ONE, TWO } TestEnum;
if (test<TestEnum>(3, ONE, TWO, ONE) == true)
cout << "all equal!\n";

the compiler says
stdarg.cpp: In function `bool test(int, ...) [with T = TestEnum]':
stdarg.cpp:13: instantiated from here
stdarg.cpp:29: warning: `TestEnum' is promoted to `int' when passed through
`...'
stdarg.cpp:29: warning: (so you should pass `int' not `TestEnum' to
`va_arg')
stdarg.cpp:31: warning: `TestEnum' is promoted to `int' when passed through
`...'

and running the program produces a SIGSEGV.

If I change the va_arg(...) lines to
va_arg(ap, int)

it works, but then the template does not work with other types any more.
Thus, I think I need to detect an enum type somehow, but how could I do
that? I searched through the FAQs and such but couldn't find help.

Thanks very much,
Klaus

 
Reply With Quote
 
 
 
 
mlimber
Guest
Posts: n/a
 
      10-12-2005
Klaus Schneider wrote:
> Hi all!
>
> I'm having trouble with a template function with variable arguments when I
> parse an enum type as variable argument. Example:
>
> template <class T>
> bool test(int num, ...)
> {
> va_list ap;
> int ind;
> bool allequal = true;
>
> va_start(ap, num);
> T lastentry((T)va_arg(ap, T));
> for(ind=0; ind<num; ind++) {
> T entry((T)va_arg(ap, T));
> /* do something with T */
> if (lastentry != entry)
> allequal = false;
> lastentry = entry;
> }
> va_end(ap);
>
> return allequal;
> }
>
> Now, if I call this template using an enum, as
> typedef enum { ONE, TWO } TestEnum;
> if (test<TestEnum>(3, ONE, TWO, ONE) == true)
> cout << "all equal!\n";
>
> the compiler says
> stdarg.cpp: In function `bool test(int, ...) [with T = TestEnum]':
> stdarg.cpp:13: instantiated from here
> stdarg.cpp:29: warning: `TestEnum' is promoted to `int' when passed through
> `...'
> stdarg.cpp:29: warning: (so you should pass `int' not `TestEnum' to
> `va_arg')
> stdarg.cpp:31: warning: `TestEnum' is promoted to `int' when passed through
> `...'
>
> and running the program produces a SIGSEGV.
>
> If I change the va_arg(...) lines to
> va_arg(ap, int)
>
> it works, but then the template does not work with other types any more.
> Thus, I think I need to detect an enum type somehow, but how could I do
> that? I searched through the FAQs and such but couldn't find help.
>
> Thanks very much,
> Klaus


Using va_arg is very much discouraged in C++ because it is not
typesafe. Mixing it with templates, as the FAQs would say, might be
legal but it certainly ain't moral! What is the problem that
necessitates va_args? Can you do it another way?

Cheers! --M

 
Reply With Quote
 
 
 
 
Klaus Schneider
Guest
Posts: n/a
 
      10-12-2005
Hi!

I want to create a vector with any number of arguments in one call, i.e.
typedef { TEMPERATURE, POTENTIAL, OUTFLOW } DataType;
Vector<DataType> v(4, TEMPERATURE, POTENTIAL, TEMPERATURE, OUTFLOW);

As it might have any number of elements, it's impossible to use overloading.
If there is another solution, I would prefer that, but I couldn't think of
one.

Thanks very much,
Klaus

mlimber wrote:
> Using va_arg is very much discouraged in C++ because it is not
> typesafe. Mixing it with templates, as the FAQs would say, might be
> legal but it certainly ain't moral! What is the problem that
> necessitates va_args? Can you do it another way?


 
Reply With Quote
 
Greg Comeau
Guest
Posts: n/a
 
      10-12-2005
In article <dij2l2$2au$(E-Mail Removed)-heidelberg.de>,
Klaus Schneider <(E-Mail Removed)-heidelberg.de.x> wrote:
>I'm having trouble with a template function with variable arguments when I
>parse an enum type as variable argument. Example:
>
>template <class T>
>bool test(int num, ...)
>{
> va_list ap;
> int ind;
> bool allequal = true;
>
> va_start(ap, num);
> T lastentry((T)va_arg(ap, T));
> for(ind=0; ind<num; ind++) {
> T entry((T)va_arg(ap, T));
> /* do something with T */
> if (lastentry != entry)
> allequal = false;
> lastentry = entry;
> }
> va_end(ap);
>
> return allequal;
>}
>
>Now, if I call this template using an enum, as
> typedef enum { ONE, TWO } TestEnum;
> if (test<TestEnum>(3, ONE, TWO, ONE) == true)
> cout << "all equal!\n";
>
>the compiler says
>stdarg.cpp: In function `bool test(int, ...) [with T = TestEnum]':
>stdarg.cpp:13: instantiated from here
>stdarg.cpp:29: warning: `TestEnum' is promoted to `int' when passed through
> `...'
>stdarg.cpp:29: warning: (so you should pass `int' not `TestEnum' to
>`va_arg')
>stdarg.cpp:31: warning: `TestEnum' is promoted to `int' when passed through
> `...'
>
>and running the program produces a SIGSEGV.
>
>If I change the va_arg(...) lines to
> va_arg(ap, int)
>
>it works, but then the template does not work with other types any more.
>Thus, I think I need to detect an enum type somehow, but how could I do
>that? I searched through the FAQs and such but couldn't find help.


From what I can see, the problem is that in C an enum might be
an int, but in C++ enum's are allowed to be shorter, that is chars.
Furthermore, enum's are promoted when passed to varags functions.
Therefore, your template is conceptually correct but implementation
wise the va_arg results in a misspeak (char vs int), hence the crash.
I seem to recall that gcc has a way to metabolize enum's but don't
know if that's something you want to consider. Then again,
I may not be stareing at your code long enough, and have gotten the
above incorrect.
--
Greg Comeau / Celebrating 20 years of Comeauity!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
 
Reply With Quote
 
Greg Comeau
Guest
Posts: n/a
 
      10-12-2005
In article <dij4r4$2lo$(E-Mail Removed)-heidelberg.de>,
Klaus Schneider <(E-Mail Removed)-heidelberg.de.x> wrote:
>Hi!
>
>I want to create a vector with any number of arguments in one call, i.e.
> typedef { TEMPERATURE, POTENTIAL, OUTFLOW } DataType;
> Vector<DataType> v(4, TEMPERATURE, POTENTIAL, TEMPERATURE, OUTFLOW);
>
>As it might have any number of elements, it's impossible to use overloading.
>If there is another solution, I would prefer that, but I couldn't think of
>one.


Not knowing where you're full code is eventually going,
it may be that you're requiremens outgrow enum's and move
into say a std::vector or std::map?
--
Greg Comeau / Celebrating 20 years of Comeauity!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
 
Reply With Quote
 
Marcus Kwok
Guest
Posts: n/a
 
      10-12-2005
In article <dij4r4$2lo$(E-Mail Removed)-heidelberg.de>,
Klaus Schneider <(E-Mail Removed)-heidelberg.de.x> wrote:
>>Hi!
>>
>>I want to create a vector with any number of arguments in one call, i.e.
>> typedef { TEMPERATURE, POTENTIAL, OUTFLOW } DataType;
>> Vector<DataType> v(4, TEMPERATURE, POTENTIAL, TEMPERATURE, OUTFLOW);
>>
>>As it might have any number of elements, it's impossible to use overloading.
>>If there is another solution, I would prefer that, but I couldn't think of
>>one.


Greg Comeau <(E-Mail Removed)> wrote:
> Not knowing where you're full code is eventually going,
> it may be that you're requiremens outgrow enum's and move
> into say a std::vector or std::map?


This sounds like it might be a reasonable solution to the OP's problem.
Push all your values into a std::vector and then iterate over the vector
in the comparison function. There may be a really simple solution using
something in <algorithm>.

--
Marcus Kwok
 
Reply With Quote
 
mlimber
Guest
Posts: n/a
 
      10-12-2005
Klaus Schneider wrote:
> mlimber wrote:
> > Using va_arg is very much discouraged in C++ because it is not
> > typesafe. Mixing it with templates, as the FAQs would say, might be
> > legal but it certainly ain't moral! What is the problem that
> > necessitates va_args? Can you do it another way?

> Hi!
>
> I want to create a vector with any number of arguments in one call, i.e.
> typedef { TEMPERATURE, POTENTIAL, OUTFLOW } DataType;
> Vector<DataType> v(4, TEMPERATURE, POTENTIAL, TEMPERATURE, OUTFLOW);
>
> As it might have any number of elements, it's impossible to use overloading.
> If there is another solution, I would prefer that, but I couldn't think of
> one.
>
> Thanks very much,
> Klaus


Hi, Klaus. Please put your responses below the quoted text. Top posting
is considered impolite.

There are several approaches beyond the dreaded elipsis. First, you
might consider the Boost.Assignment library
(http://www.boost.org/libs/assign/doc/). It allows you to write code
like this:

std::vector<int> v;
v += 1,2,3,4,5,6,7,8,9;

Alternately, you can roll your own intialization with method chaining
(cf. http://www.parashift.com/c++-faq-lit...l#faq-10.18-):

#include <vector>
using namespace std;

template<typename T>
class Initializer
{
vector<T> v_;
public:
Initializer& Add( const T& t ) { v_.push_back(t); return *this; }
operator vector<T>() const { return v_; }
};

// Note: no need for typedef for the enum in C++
enum DataType { TEMPERATURE, POTENTIAL, OUTFLOW };

int main()
{
vector<DataType> v = Initializer<DataType>()
.Add( TEMPERATURE )
.Add( POTENTIAL )
.Add( TEMPERATURE )
.Add( OUTFLOW );
// ...
return 0;
}

Cheers! --M

 
Reply With Quote
 
Klaus Schneider
Guest
Posts: n/a
 
      10-12-2005
>> Not knowing where you're full code is eventually going,
>> it may be that you're requiremens outgrow enum's and move
>> into say a std::vector or std::map?

>
> This sounds like it might be a reasonable solution to the OP's problem.
> Push all your values into a std::vector and then iterate over the vector
> in the comparison function. There may be a really simple solution using
> something in <algorithm>.

It seems you misunderstood what I was trying to do. I have
template <class T>
class Vector : public QValueVector<T>
{
/* just add a new constructor with variable arguments */
};
typedef { TEMPERATURE, POTENTIAL, OUTFLOW } DataType;

I want to have a function
loadData(const char* filename, Vector<DataType> type, Vector<int> indices)
which I want to call as
loadData("experiment.dat",
Vector<DataType>(4,TEMPERATURE, POTENTIAL, TEMPERATURE, OUTFLOW),
Vector<int>(4, 7, 10, 5, 2));

Of course I could do
QValueVector<DataType> types(4);
types.append(TEMPERATURE);
types.append(POTENTIAL);
types.append(OUTFLOW);
types.append(TEMPERATURE);
QValueVector<int> indices(4);
indices.append(7);
indices.append(10);
indices.append(5);
indices.append(2);
loadData(filename, types, indices);

but this is confusing because you don't see the structure of the data
without looking twice. Thus, I thought I'd enhance QValueVector by a new
constructor... but somehow it didn't work as I thought it would.

Do you have suggestions for a "clean" solution to the problem?

Thanks,
Klaus

 
Reply With Quote
 
Klaus Schneider
Guest
Posts: n/a
 
      10-12-2005
mlimber wrote:
> Klaus Schneider wrote:
>> mlimber wrote:
>> > Using va_arg is very much discouraged in C++ because it is not
>> > typesafe. Mixing it with templates, as the FAQs would say, might be
>> > legal but it certainly ain't moral! What is the problem that
>> > necessitates va_args? Can you do it another way?

>> Hi!
>>
>> I want to create a vector with any number of arguments in one call, i.e.
>> typedef { TEMPERATURE, POTENTIAL, OUTFLOW } DataType;
>> Vector<DataType> v(4, TEMPERATURE, POTENTIAL, TEMPERATURE, OUTFLOW);
>>
>> As it might have any number of elements, it's impossible to use
>> overloading. If there is another solution, I would prefer that, but I
>> couldn't think of one.
>>
>> Thanks very much,
>> Klaus

>
> Hi, Klaus. Please put your responses below the quoted text. Top posting
> is considered impolite.
>
> There are several approaches beyond the dreaded elipsis. First, you
> might consider the Boost.Assignment library
> (http://www.boost.org/libs/assign/doc/). It allows you to write code
> like this:
>
> std::vector<int> v;
> v += 1,2,3,4,5,6,7,8,9;
>
> Alternately, you can roll your own intialization with method chaining
> (cf. http://www.parashift.com/c++-faq-lit...l#faq-10.18-):
>
> #include <vector>
> using namespace std;
>
> template<typename T>
> class Initializer
> {
> vector<T> v_;
> public:
> Initializer& Add( const T& t ) { v_.push_back(t); return *this; }
> operator vector<T>() const { return v_; }
> };
>
> // Note: no need for typedef for the enum in C++
> enum DataType { TEMPERATURE, POTENTIAL, OUTFLOW };
>
> int main()
> {
> vector<DataType> v = Initializer<DataType>()
> .Add( TEMPERATURE )
> .Add( POTENTIAL )
> .Add( TEMPERATURE )
> .Add( OUTFLOW );
> // ...
> return 0;
> }


Thanks very much! That is really what I needed...
Klaus

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
ENUM server for private ENUM kael UK VOIP 2 02-25-2007 11:54 AM
enum: display elements of an enum specified at runtime Jerminia Java 3 10-07-2005 10:08 PM
enum within an enum - Java 6 06-13-2005 12:51 AM
Including an enum within another enum, possible? mrhicks C Programming 2 06-10-2004 03:00 AM
How to enum an enum? Ernst Murnleitner C++ 5 11-13-2003 11:06 AM



Advertisments