template with stdarg: enum problem

266 views
Skip to first unread message

Klaus Schneider

unread,
Oct 12, 2005, 9:22:12 AM10/12/05
to
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

unread,
Oct 12, 2005, 9:44:06 AM10/12/05
to

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

unread,
Oct 12, 2005, 9:59:34 AM10/12/05
to
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

Greg Comeau

unread,
Oct 12, 2005, 10:48:45 AM10/12/05
to
In article <dij2l2$2au$1...@news.urz.uni-heidelberg.de>,

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

unread,
Oct 12, 2005, 10:56:15 AM10/12/05
to
In article <dij4r4$2lo$1...@news.urz.uni-heidelberg.de>,

Klaus Schneider <klaus.s...@iup.uni-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?

Marcus Kwok

unread,
Oct 12, 2005, 11:07:22 AM10/12/05
to
In article <dij4r4$2lo$1...@news.urz.uni-heidelberg.de>,
Klaus Schneider <klaus.s...@iup.uni-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 <com...@panix.com> 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

mlimber

unread,
Oct 12, 2005, 12:02:53 PM10/12/05
to
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-lite/ctors.html#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

unread,
Oct 12, 2005, 12:04:17 PM10/12/05
to
>> 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

Klaus Schneider

unread,
Oct 12, 2005, 12:14:08 PM10/12/05
to

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

Reply all
Reply to author
Forward
0 new messages