Reputation: 611
Does C++17 (or earlier but not c++20) allow this?
I need a type_traited conditional class, like a bitset with an internal 32 or 64 unsigned integer storage, depending if the template argument N is lesser then 32 or greater (please forget about more than 64 bits).
But the constraint is to finally implement two and only two classes for all possible cases. Next source code defines the problem using static and running time asserts:
Coliru link: http://coliru.stacked-crooked.com/a/d53a5b00bd828fb5
#include <cassert>
#include <iostream>
#include <type_traits>
struct bitset32
{
bitset32() : bits(0) { }
bitset32(int _bits) : bits(_bits) { }
const int bits;
uint32_t value;
};
struct bitset64
{
bitset64() : bits(0) { }
bitset64(int _bits) : bits(_bits) { }
const int bits;
uint64_t value;
};
template <int N>
using bitset = std::conditional_t<(N<=32), bitset32, bitset64>;
int main ()
{
static_assert(std::is_same<bitset<1>, bitset<2>>::value);
static_assert(std::is_same<bitset<33>, bitset<34>>::value);
static_assert(!std::is_same<bitset<1>, bitset<33>>::value);
bitset<1> var1;
bitset<15> var2;
bitset<32> var3;
bitset<64> var4;
assert(var1.bits == 1);
assert(var2.bits == 15);
assert(var3.bits == 32);
assert(var4.bits == 64);
}
Any solution is welcomend even if it changes the basic types and uses inheritance or whatever other mechanism necessary, but please, do not offer using a template function returning an object in the style of template<int N> make_bitset { return Bitset<N>(N); }
because it is needed to implement variables using this constructo Bitset<N> variable_name
.
Upvotes: 1
Views: 171
Reputation: 66200
A new hypothesis, CTAD based
#include <cstdint>
#include <iostream>
#include <type_traits>
template <std::size_t>
struct BitSet;
template <>
struct BitSet<32u>
{
template <typename ... Ts>
BitSet (Ts...) {}
std::uint32_t value;
};
template <>
struct BitSet<64u>
{
template <typename ... Ts>
BitSet (Ts...) {}
std::uint64_t value;
};
template <typename ... Ts>
BitSet (Ts...) -> BitSet<(32 < sizeof...(Ts) ? 64u : 32u)>;
int main()
{
auto b1 = BitSet{1};
auto b2 = BitSet{2};
auto b3 = BitSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39};
auto b4 = BitSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49};
static_assert( std::is_same_v<decltype(b1), decltype(b2)> );
static_assert( std::is_same_v<decltype(b1), BitSet<32u>> );
static_assert( std::is_same_v<decltype(b3), decltype(b4)> );
static_assert( std::is_same_v<decltype(b3), BitSet<64u>> );
}
Upvotes: 1
Reputation: 180594
You can just make bitset32
and bitset64
templates like
template <std::size_t BitsUsed>
struct bitset32
{
bitset32() : bits(BitsUsed) { }
bitset32(int _bits) : bits(_bits) { }
const int bits;
uint32_t value;
};
template <std::size_t BitsUsed>
struct bitset64
{
bitset64() : bits(BitsUsed) { }
bitset64(int _bits) : bits(_bits) { }
const int bits;
uint64_t value;
};
and now the default constructor will pull in the correct number of bits. Then you just need to modify your alias like
template <int N>
using bitset = std::conditional_t<(N<=32), bitset32<N>, bitset64<N>>;
and you get the behavior you are asking for.
This will not work if you want to store a bitset<5>
in the same container as a bitset<32>
though since different template instantiations create distinct type.
Upvotes: 0