I want to have a bitset constexpr variable in my program. bitset can have unsigned long long value as a constructor which is 64bit value, I need 100 bit value. As per this Q&A, we can use constructor that takes a string as an argument and initialize it that way, but it won't be constexpr value.
Is there any possible way?
the constructor std::bitset<N>(uint64_t) is the only useful constexpr callable constructor here:
constexpr bitset(unsigned long long _Val) noexcept : _Array{static_cast<_Ty>(_Need_mask ? _Val & _Mask : _Val)} {}
and that will only provide 64 bits of information.
But since it is possible to initalize a std::bitset at compile time with another std::bitset, in theory you could make a constexpr function that initializes a std::bitset and returns that, like this:
template<size_t N>
constexpr std::bitset<N> make_bitset(const char* x) {
std::bitset<N> result;
for (int i = 0; x && x[i] != '\0'; ++i) {
result.set(i, x[i] - '0');
}
return result;
}
sadly this doesn't compile as std::bitset<N>::set is not declared constexpr. But looking at the set function, in theory this function could be declared constexpr:
bitset& _Set_unchecked(size_t _Pos, bool _Val) noexcept { // set bit at _Pos to _Val, no checking
auto& _Selected_word = _Array[_Pos / _Bitsperword];
const auto _Bit = _Ty{1} << _Pos % _Bitsperword;
if (_Val) {
_Selected_word |= _Bit;
} else {
_Selected_word &= ~_Bit;
}
return *this;
}
but until then, you can't initialize a std::bitset with more than 64 bits of information at compile time.
Unfortunately, constexpr std::bitset's constructors are limited to
default one,
and the one taking unsigned long long.
In addition, its mutators (set, operator[], ...) are not constexpr neither, so you cannot create a constexpr "factory".
You have to create your own bitset (or use one from another library).
Related
I'm writing a hashing function to help speed up string comparisons.
My codebase compares strings against a lot of const char[] constants, and it would be ideal if I could work with hashes instead. I went ahead and translated xxHash to modern C++, and I have a working prototype that does work at compile time, but I'm not sure what the function definition should be for the main hashing function.
At the moment, I have this:
template <size_t arr_size>
constexpr uint64_t xxHash64(const char(data)[arr_size])
{...}
This does work, and I am able to do a compile time call like this
constexpr char myString[] = "foobar";
constexpr uint64_t hashedString = xxHash64<sizeof myString>(myString);
[Find a minimal example here]
All good so far, but I would like to add a user-defined literal wrapper function for some eye candy, and this is where the problem lies.
UDLs come with a fixed prototype, as specified here
The Microsoft doc stipulates "Also, any of these operators can be defined as constexpr".
But when I try to call my hashing function from a constexpr UDL:
constexpr uint64_t operator "" _hashed(const char *arr, size_t size) {
return xxHash64<size>(arr);
}
function "xxHash64" cannot be called with the given argument list
argument types are: (const char*)
And the error does make sense. My function expects a character array, and instead it gets a pointer.
But if I were to modify the definition of my xxHash64 function to take a const char *, I can no longer work in a constexpr context because the compiler needs to resolve the pointer first, which happens at runtime.
So am I doing anything wrong here, or is this a limitation of UDLs or constexpr functions as a whole?
Again, I'm not 100% sure the templated definition at the top is the way to go, but I'm not sure how else I could read characters from a string at compile time.
I'm not limited by any compiler version or library. If there is a better way to do this, feel free to suggest.
there is no problem to call constexpr function with constexpr pointer as constant expression
constexpr uint64_t xxHash64(const char* s){return s[0];}
constexpr uint64_t operator "" _g(const char *arr,std::size_t){
return xxHash64(arr);
}
int main()
{
xxHash64("foo");
constexpr auto c = "foobar"_g;
return c;
}
would just work fine.
with c++20, you can also get the size as constant expression with string literal operator template.
#include <cstdint>
template <std::size_t arr_size>
constexpr std::uint64_t xxHash64(const char(&data)[arr_size]){
return data[0];
}
// template <std::size_t N> // can also be full class template (with CTAD)
struct hash_value{
std::uint64_t value;
template <std::size_t N>
constexpr hash_value(const char(&p)[N]):value(xxHash64(p)){}
};
template < hash_value v >
constexpr std::uint64_t operator ""_hashed() { return v.value; }
int main()
{
constexpr auto v = "foobar"_hashed;
return v;
}
I have code C++11:
template<std::size_t n>
static inline constexpr uint32_t mask() noexcept
{
static_assert(n <= 32, "!");
using list = uint32_t[];
return list{
0x0u,
0x1u, 0x3u, 0x7, 0xfu, 0x1fu, 0x3fu, 0x7fu, 0xffu,
0x1ffu, 0x3ffu, 0x7ffu, 0xfffu, 0x1fffu, 0x3fffu, 0x7fffu, 0xffffu,
0x1ffffu, 0x3ffffu, 0x7ffffu, 0xfffffu, 0x1fffffu, 0x3fffffu, 0x7fffffu, 0xffffffu,
0x1ffffffu, 0x3ffffffu, 0x7ffffffu, 0xfffffffu, 0x1fffffffu, 0x3fffffffu, 0x7fffffffu, 0xffffffffu
} [ n ];
}
Q: where is stored list array? (in static memory, auto memory, or nowhere stored)?
In a normal function, it would be a temporary, stored in automatic memory. Since n is a compile time constant, it may be optimised to simply return the value, removing the array.
However, this is constexpr, so the return value should be computed at compile time. The array should not exist at run time at all.
Since n in the function can not be a variable, e.g.
size_t n;
std::cin >> n;
std::cout << mask<n>() << std::endl;
will fail to compile, because n is not a constant at compile-time, the compiler wouldn't need to store the array at all. In general, a constexpr function should not generate any "code" other than some sort of constant value.
My compiler appears to not accept the code posted here - probably because it's a bit ancient by now (it's a gcc 4.6.3 - I also tried clang++, but it fails because it tries to use the 4.6.3 headers, which apparently isn't in "clang flavour").
Of course, it's much easier to write this:
template<std::size_t n>
inline constexpr uint32_t mask() noexcept
{
static_assert(n <= 32, "!");
return (1u << n) -1;
}
To cope with the special case where n == 32 (and avoiding UB, although in most archtiectures, the above would probably do the right thing):
template<>
inline constexpr uint32_t mask<32>() noexcept
{
return ~0;
}
I'm trying to create a compile-time bit mask using metaprograming techniques, my idea is to create something like this:
unsigned int Mask3 = Mask<2>(); // value = 0x03 = b00000000000000000000000000000011
unsigned int Mask3 = Mask<3>(); // value = 0x07 = b00000000000000000000000000000111
unsigned int Mask3 = Mask<7>(); // value = 0x7F = b00000000000000000000000001111111
The code that I'm trying is this:
template <const unsigned int N> const unsigned int Mask()
{
if (N <= 1)
{
return 1;
}
else
{
return ((1 << N) | Mask<N - 1>());
}
}
return 1;
But it result in tons pairs of warnings:
warning C4554: '<<' : check operator precedence for possible error
warning C4293: '<<' : shift count negative or too big
And in the end, the compile error:
error C1202: recursive type or function dependency context too complex.
So, I deduce that the recursivity never ends and falls into a compiler infinite loop but I'm don't understanding WHY.
As has already been pointed out, you're depending on a runtime check to
stop a compile time recursion, which can't work. More importantly,
perhaps, for what you want to do, is that you're defining a function,
which has no value until you call it. So even after you stop the
recursion with a specialization, you still have a nested sequence of
functions, which will be called at runtime.
If you want full compile time evaluation, you must define a static data
member of a class template, since that's the only way a compile time
constant can appear in a template. Something like:
template <unsigned int N>
struct Mask
{
static unsigned int const value = (1 << (N - 1)) | Mask<N - 1>::value;
};
template <>
struct Mask<0>
{
static unsigned int const value = 0;
};
(I've also corrected the numerical values you got wrong.)
Of course, you don't need anything this complicated. The following
should do the trick:
template <unsigned int N>
struct Mask
{
static unsigned int const value = (1 << (N + 1)) - 1;
};
template <>
struct Mask<0>
{
static unsigned int const value = 0;
};
(You still need the specialization for 0. Otherwise, 0 means all bits
set.)
Finally, of course: to access the value, you need to write something
like Mask<3>::value. (You might want to wrap this in a macro.)
It doesn't need to be recursive. This should work just fine :
template <const unsigned int N> const unsigned int Mask()
{
return ((1 << N) - 1);
}
It doesn't even need to be a template really. An (inlined) function is ok.
Note that if you want to support any value of N, specifically N >= sizeof(unsigned int) * CHAR_BIT, you probably want to treat those as a special case.
A template is created at compile time, but you are relying on run time behavior to stop the recursion.
For example, if you instantiate Mask<2>, it is going to use Mask<1>, which is going to use Mask<0>, which is going to use Mask<-1>, etc.
You have a runtime check for N being <= 1, but this doesn't help when it's compiling. It still creates an infinite sequence of functions.
To blunt template instantiation recursion you need to introduce one explicit specialization:
template <0> const unsigned int Mask()
{
return 1;
}
Your recursion never ends, because compiler tries to generate template implementation for both if-branches. So, when it generates Mask<0> it also generates Mask<0xffffffff> and so on
C++11 -- no recursion or templates:
constexpr unsigned mask(unsigned N) { return unsigned(~(-1<<N)); }
So far the answers only addressed the second error (C1202), but you asked more than that.
Warning C4554 is caused by a Microsoft compiler bug involving template parameters and the << operator. So, (1 << N) generates a warning. If N were an ordinary parameter, there would be no warning of course.
The very simple workaround is to use (1 << (N)) instead of (1 << N), and C4554 goes away!
I'm using a template to convert integral types into a string representation of their binary values. I used the following:
template<typename T>
std::string ToBinary(const T& value)
{
const std::bitset<std::numeric_limits<T>::digits + 1> bs(value);
const std::string s(bs.to_string());
return s;
}
It works for int but doesn't compile with unsigned int :
unsigned int buffer_u[10];
int buffer_i[10];
...
ToBinary(buffer_i[1]); //compile and works
ToBinary(buffer_u[1]); //doesn't compile -- ambiguous overload
Could you explain why?
EDIT:
Yes, I'm using VS2010
Not your ToBinary call is ambiguous, its the constructor call of bitset with an unsigned value. Unfortunately this is a VC++ Bug: http://connect.microsoft.com/VisualStudio/feedback/details/532897/problems-constructing-a-bitset-from-an-unsigned-long-in-the-vc-rc
Edit - Workaround:
template<>
std::string ToBinary<unsigned int>(const unsigned int& value)
{
const std::bitset<std::numeric_limits<unsigned int>::digits> bs(static_cast<unsigned long long>(value));
return bs.to_string();
}
If you look at the standard (FDIS n3290), then you see that std::bitset has multiple constructors:
First there is this one:
20.5.1 bitset constructors [bitset.cons]
constexpr bitset(unsigned long long val) noexcept;
Effects: Constructs an object of class bitset, initializing the
first M bit positions to the corresponding bit values in val. M is the
smaller of N and the number of bits in the value representation (3.9)
of unsigned long long. If M < N, the remaining bit positions are
initialized to zero.
Then there is also this one, which I suspect might be might cause things to become ambigious, when you call it with unsigned int
template <class charT>
explicit bitset(
const charT* str,
typename basic_string<charT>::size_type n = basic_string<charT>::npos,
charT zero = charT(’0’), charT one = charT(’1’));
Effects: Constructs an object of class bitset as if by
bitset( n == basic_string<charT>::npos ? basic_string<charT>(str) :
basic_string<charT>(str, n), 0, n, zero, one)
Are you using VC10? There is already an issue reported: Microsoft connect. Also I'd guess that you might be able to fix it by casting the type to int if it is 32 bit, like this:
string s = ToBinary(*reinterpret_cast<int*>(&buffer_u[1]));
This can be done inside of the method as well if needed. The result of the reinterpret should not be used for arithmetics anymore, though. ;)
Works fine as workaround for me (but looks quite ugly)
template<typename T>
std::string ToBinary(const T& value)
{
switch (sizeof(T))
{
case 8:
return std::bitset<std::numeric_limits<T>::digits + 1>(*reinterpret_cast<const long*>(&value)).to_string();
case 4:
return std::bitset<std::numeric_limits<T>::digits + 1>(*reinterpret_cast<const int*>(&value)).to_string();
case 2:
return std::bitset<std::numeric_limits<T>::digits + 1>(*reinterpret_cast<const short*>(&value)).to_string();
case 1:
return std::bitset<std::numeric_limits<T>::digits + 1>(*reinterpret_cast<const char*>(&value)).to_string();
}
return "n/a";
}
I need to extract and decode the bits (idx, idx+1, ... idx+n_bits) from a given boost dynamic_bitset.
I have created the following solution:
boost::dynamic_bitset<> mybitset(...);
// build mask 2^{idx+n_bits} - 2^{idx}
const boost::dynamic_bitset<> mask(mybitset.size(), (1 << idx+n_bits) - (1 << idx));
// shift the masked result idx times and get long
unsigned long u = ((mybitset & mask) >> idx ).to_ulong();
It works well, but as this code is critical for the performance of my application, I am curious if there exists a better way to achieve this?
The solution is easy:
#include <tuple>
using std::get;
using std::tuple;
using std::make_tuple;
#include <boost/dynamic_bitset.hpp>
using boost::dynamic_bitset;
template <typename Block, typename Allocator>
unsigned block_index(const boost::dynamic_bitset<Block, Allocator>& b, unsigned pos)
{ return pos / b.bits_per_block; }
namespace boost {
template <>
inline void
to_block_range(const dynamic_bitset<>& b, tuple<unsigned, unsigned, unsigned long&> param)
{
{
unsigned beg = get<0>(param);
unsigned len = get<1>(param);
unsigned block1 = block_index(b, beg);
unsigned block2 = block_index(b, beg + len -1);
unsigned bit_index = beg % b.bits_per_block;
unsigned long bitmask = (1 << len) - 1;
get<2>(param) = ((b.m_bits[block1] >> bit_index) |
(b.m_bits[block2] << (b.bits_per_block - bit_index) )) &
bitmask;
return;
}
}
}
unsigned long res;
to_block_range(bits, make_tuple(pos, len, std::ref(res)));
To call:
boost::dynamic_bitset<> bits;
unsigned long result;
to_block_range(bits, t_extract_range{begin_bit, length_bits, result});
There is no direct, native support in dynamic_bitset.
To get a range of bits, you have to get inside dynamic_bitset, get access to the underlying storage, and extract the bits yourself.
The code to do this is trivial but the data (dynamic_bitset::m_bits) is inside the private part of the class. There are three ways to hack past the private wall:
Pretend your compiler is non-conforming.
#define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS. This changes private to public by changing BOOST_DYNAMIC_BITSET_PRIVATE.
Hacking the dynamic_bitset.hpp header to expose m_bits.
The third solution is to work around the current code.
(1) and (2) are brittle, frontal assaults which will be a maintenance nightmare.
Luckily for (3), there are template functions which are friends of dynamic_bitset. We can substitute our own function to do our own extraction by taking over (specialising) this template.
template <typename Block, typename Allocator, typename BlockOutputIterator>
inline void
to_block_range(const dynamic_bitset<Block, Allocator>& b,
BlockOutputIterator result)
{
std::copy(b.m_bits.begin(), b.m_bits.end(), result);
}
The canonical template function copies the entire bitset to iterator BlockOutputIterator which is not what we want.
We are going to specialise boost::to_block_range using a single custom type in place of BlockOutputIterator which will hold all 3 i/o parameters: namely
begin_bit,
length_of_range and
destination.
Providing you call to_block_range with the requisite type, it will call your own function instead of the standard template, but with full access to the internals as well. You have essentially subverted the c++ access specification system!
N.B. The example code does no error checking. No attempt to make sure
that the range fits in unsigned long or
that the range does not exceed the bounds of the bitset or
that the bitset uses unsigned longs internally.