Connecting Tech Pros Worldwide Help | Site Map

template with stdarg: enum problem

Klaus Schneider
Guest
 
Posts: n/a
#1: Oct 12 '05
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

mlimber
Guest
 
Posts: n/a
#2: Oct 12 '05

re: template with stdarg: enum problem


Klaus Schneider wrote:[color=blue]
> 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[/color]

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

Klaus Schneider
Guest
 
Posts: n/a
#3: Oct 12 '05

re: template with stdarg: enum problem


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:[color=blue]
> 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?[/color]

Greg Comeau
Guest
 
Posts: n/a
#4: Oct 12 '05

re: template with stdarg: enum problem


In article <dij2l2$2au$1@news.urz.uni-heidelberg.de>,
Klaus Schneider <klaus.schneider@iup.uni-heidelberg.de.x> wrote:[color=blue]
>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.[/color]

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?
Greg Comeau
Guest
 
Posts: n/a
#5: Oct 12 '05

re: template with stdarg: enum problem


In article <dij4r4$2lo$1@news.urz.uni-heidelberg.de>,
Klaus Schneider <klaus.schneider@iup.uni-heidelberg.de.x> wrote:[color=blue]
>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.[/color]

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?
Marcus Kwok
Guest
 
Posts: n/a
#6: Oct 12 '05

re: template with stdarg: enum problem


In article <dij4r4$2lo$1@news.urz.uni-heidelberg.de>,
Klaus Schneider <klaus.schneider@iup.uni-heidelberg.de.x> wrote:[color=blue][color=green]
>>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.[/color][/color]

Greg Comeau <comeau@panix.com> wrote:[color=blue]
> 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?[/color]

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
mlimber
Guest
 
Posts: n/a
#7: Oct 12 '05

re: template with stdarg: enum problem


Klaus Schneider wrote:[color=blue]
> mlimber wrote:[color=green]
> > 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?[/color]
> 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[/color]

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...ml#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

Klaus Schneider
Guest
 
Posts: n/a
#8: Oct 12 '05

re: template with stdarg: enum problem


>> Not knowing where you're full code is eventually going,[color=blue][color=green]
>> it may be that you're requiremens outgrow enum's and move
>> into say a std::vector or std::map?[/color]
>
> 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>.[/color]
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

Klaus Schneider
Guest
 
Posts: n/a
#9: Oct 12 '05

re: template with stdarg: enum problem


mlimber wrote:[color=blue]
> Klaus Schneider wrote:[color=green]
>> mlimber wrote:[color=darkred]
>> > 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?[/color]
>> 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[/color]
>
> 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...ml#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;
> }[/color]

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

Closed Thread