const or not const, that's the question here! :-)

A

Adem24

The compiler which I have to use in a project doesn't like
the following construct. It says: 'bitset' : invalid template argument.
It means that it wants only a static-like const N as a template argument,
ie. it doesn't accept a const variable that was initialized
from an auto variable (here i), for passing it as a template
argument to bitset<n>.

Is this a compiler limitation or is my code not standard conform?
Can you think of any workaround construct to achieve this
or an alternate functionality with such a compiler?

Of course if I change the line to read for example
const size_t N = 1U << 16;
then it compiles ok. But I need to loop 22 times here...

#include <bitset>
void f()
{
for (size_t i = 1; i <= 22; ++i)
{
const size_t N = 1U << i;
bitset<N> bv;

bv.set(7);
//...
}
}
 
K

Kai-Uwe Bux

Adem24 said:
The compiler which I have to use in a project doesn't like
the following construct. It says: 'bitset' : invalid template argument.
It means that it wants only a static-like const N as a template argument,
ie. it doesn't accept a const variable that was initialized
from an auto variable (here i), for passing it as a template
argument to bitset<n>.

Is this a compiler limitation or is my code not standard conform?
Can you think of any workaround construct to achieve this
or an alternate functionality with such a compiler?

Of course if I change the line to read for example
const size_t N = 1U << 16;
then it compiles ok. But I need to loop 22 times here...

#include <bitset>
void f()
{
for (size_t i = 1; i <= 22; ++i)
{
const size_t N = 1U << i;
bitset<N> bv;

Your code is wrong. This N is not a compile time constant. Templates only
work with those.

You might want to have a look into dynamic_bitset from boost or
bv.set(7);
//...
}
}


Best

Kai-Uwe Bux
 
E

Eric Pruneau

Adem24 said:
The compiler which I have to use in a project doesn't like
the following construct. It says: 'bitset' : invalid template argument.
It means that it wants only a static-like const N as a template argument,
ie. it doesn't accept a const variable that was initialized
from an auto variable (here i), for passing it as a template
argument to bitset<n>.

Is this a compiler limitation or is my code not standard conform?
Can you think of any workaround construct to achieve this
or an alternate functionality with such a compiler?

Of course if I change the line to read for example
const size_t N = 1U << 16;
then it compiles ok. But I need to loop 22 times here...

#include <bitset>
void f()
{
for (size_t i = 1; i <= 22; ++i)
{
const size_t N = 1U << i;
bitset<N> bv;

bv.set(7);
//...
}
}

Your code cannot compile. N must be a compile time evaluatable constant. In
your case, N is constant but unknow to the compiler at compile time because
of i.
 
K

kwikius

Kai-Uwe Bux said:
Your code is wrong. This N is not a compile time constant. Templates only
work with those.

You could probably set this up fairly simply to use compile time recursion.
Use a functor templated on N which calls N-1 and specialize it for zero (or
other way up ) case etc...

regards
Andy Little
 
K

Kai-Uwe Bux

kwikius said:
You could probably set this up fairly simply to use compile time
recursion. Use a functor templated on N which calls N-1 and specialize it
for zero (or other way up ) case etc...

Yes one could do that. But why? You end up with some monstrous incantation
that will fill your screen with book size error messages if you get a tiny
detail wrong; and for which gain? The algorithms underlying bitset<N> are
mostly just bit fiddling iterated over a vector of unsigned long (int?)
anyway. I would be rather surprised if it matters performancewise whether
the length of that buffer is fixed at compile time or at run time.

I love templates, I really do; but in a case like this, I think they would
make the code worse (e.g., harder to maintain and change).


Best

Kai-Uwe Bux
 
A

Andy Little

kwikius said:
Only one way to find out....

<... usual inertia elided ...>

Apologies That was a bit fierce, however using compile time loop
unrolling is a useful technique, and the OP was asking why it wasnt
didnt seem possible. I was merely pointing out that it is possible. In
some cases the compiler may do loop unrolling for you, but doing it
explicitly using compile time recursion is one less uncertainty/ layer
of complexity for the optimiser.

Interestingly, looking at std::bitset, Its kind of a weird hybrid
because the length is fixed but many ops are runtime.

As an example one could add a bitset.flip<Pos>() function to accompany
bitset.flip(pos). The first version being again easier to optimise and
all the information re the op is available at compile time unlike the
runtime parameter, and very usefully, the range can be checked at
compile time too, so there is no need of a runtime check and possible
exception, unlike appears to be the case in the runtime flip (which
throws an exception on out of range). The same applies to many (probably
nearly all) ops in bitset AFAICS.

regards
Andy Lttle
 
F

Frank Birbacher

Hi!
You could probably set this up fairly simply to use compile time recursion.
Use a functor templated on N which calls N-1 and specialize it for zero (or
other way up ) case etc...

You could probably fix this fairly simple by using the same size in each
loop:

const size_t maxlen = 22;
bitset<1 << maxlen> bv;
for (size_t i = 1; i <= maxlen; ++i)
{
const size_t N = 1U << i;

bv.set(7);
//...
}

Frank
 
B

Bo Persson

Andy said:
Apologies That was a bit fierce, however using compile time loop
unrolling is a useful technique, and the OP was asking why it wasnt
didnt seem possible. I was merely pointing out that it is possible.
In some cases the compiler may do loop unrolling for you, but doing
it explicitly using compile time recursion is one less uncertainty/
layer of complexity for the optimiser.

Interestingly, looking at std::bitset, Its kind of a weird hybrid
because the length is fixed but many ops are runtime.

As an example one could add a bitset.flip<Pos>() function to
accompany bitset.flip(pos). The first version being again easier
to optimise and all the information re the op is available at
compile time unlike the runtime parameter, and very usefully, the
range can be checked at compile time too, so there is no need of a
runtime check and possible exception, unlike appears to be the case
in the runtime flip (which throws an exception on out of range).
The same applies to many (probably nearly all) ops in bitset AFAICS.

Any decent optimizer can do that anyway, when pos is a compile time
constant. That saves you from modifying the application code when that
condition changes.


Bo Persson
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top