1

I can create a C++11 Template function to explicitly convert a bitset into an unsigned long:

template<size_t N>
unsigned long U(bitset<N> x) {
    return x.to_ulong();
}

// Explicit conversion
unsigned long y = U(bitset<4>("1010"));

Is there a way to "implicitly" convert bitset to an unsigned long using a C++11 template helper function. For Example, if I assign a bitset to an unsigned long, then I want it to automatically convert the bitset to the correct type:

// What Template Function in C++11?

// Implicit Conversion
unsigned long z = bitset<4>("1010");

(If its not possible to create an implicit convertion rule to convert to "unsigned long using a C++11 template function, its also acceptable to derive a new class from bitset that has casting function to unsigned long. Is that possible as well?)

Bimo
  • 5,987
  • 2
  • 39
  • 61
  • 2
    Is `unsigned long z = bitset<4>("1010").to_ulong();` acceptable? – DeiDei Jun 20 '18 at 15:52
  • no, because it too messy to keep converting it.... I have it used in complicated Boolean equations across several files... it just looks ulgy if its not implicitly converted... – Bimo Jun 20 '18 at 15:55
  • 1
    To be honest, if your bitset is not too big, you could directly use a binary literal: `auto z = 0b1010ul;`. On the other hand having `bitset` implicitly convertible to `unsigned long` might cause more problems than it solves. – DeiDei Jun 20 '18 at 15:57
  • that's a good point... except, I really want to use bitset because it has bounds checking and doesn't allow my inputs to go out of of range of the specified number of bits. – Bimo Jun 20 '18 at 16:01
  • Ok, agreed. If you are writing normal programmer code it’s good enough to use c++14 0b0010...etc, But, I would like to keep track of bit widths because it’s modeling hardware in c++ like verilog, systemc, vhdl. etc. – Bimo Jun 21 '18 at 04:46
  • I thought about just throwing away bitset and creating a class wrapper around uint64_t instead that enforces a given bit width onto input and output variables to logical function as a sanity check of doing all the logic equations in 64 bit ints. – Bimo Jun 21 '18 at 04:53
  • It would be nice if for instance the bitset replacement class could keep track of how the bitwidths expand when you add or multiple bit vectors of different bit lengths...but I suppose I can just hand calculate the bit width of the final result and assign the truncation width for output bit vector using uint64_t class wrapper... if that makes sense to anyone.. – Bimo Jun 21 '18 at 05:00

3 Answers3

7

To implicitly convert A to B, either:

  • B must have a non-explicit constructor taking A, or
  • A must have a non-explicit conversion operator B().

Both of these must be member functions only.

Since you cannot modify std::bitset or unsigned long the answer is: no, you cannot implicitly convert std::bitset to unsigned long. Only explicitly.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • I'm willing to derive a new class from bitset to fix the problem.. how would you do it in this case? – Bimo Jun 20 '18 at 16:02
  • For most `std` classes, you are [not supposed to derive from them](https://stackoverflow.com/questions/6006860/why-should-one-not-derive-from-c-std-string-class). You could encapsulate it in a new class though. – Max Langhof Jun 20 '18 at 16:06
  • Is this possible in C++11: template operator unsigned long(bitset& x) {return x.to_ulong();} ?? (A helper function that satisfies bullet two) – Bimo Jun 20 '18 at 16:08
2

You could wrap std::bitset in your own implicitly convertible class:

template<size_t N>
class MyBitset
{
public:
    // constructors elided here

    operator unsigned long()
    {
        return _bitset.to_ulong();
    }

    operator std::bitset<N>()
    {
        return _bitset; // Note that you get a copy here.
    }

private:
    std::bitset<N> _bitset;
};

Demo

If you are trying to derive from non-polymorphic classes in namespace std (i.e. those without virtual destructors), you are not writing idiomatic C++, don't do it. Whether the above is really a solution to your problem we can't tell. If all you need is unsigned long constants from your bitstrings, you could skip the class wrapper and replace its constructors with templated functions directly:

template<size_t N, class CharT>
unsigned long toUlong(const CharT* str,
                 typename std::basic_string<CharT>::size_type n =
                     std::basic_string<CharT>::npos,
                 CharT zero = CharT('0'),
                 CharT one = CharT('1'))
{
    return std::bitset<N>(str, n, zero, one).to_ulong();
}

Demo

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • I like this idea of using a wrapper... it hides all the public functions of bitset and lets you define your own... – Bimo Jun 20 '18 at 16:28
0

Another Solution based on Maxim's Bullet 2:

template<size_t N>
class bits : public bitset<N> {
public:
    bits(unsigned long num) : bitset<N>(num) {}
    bits(char* binstr) : bitset<N>(binstr){}

    operator unsigned long() {
        return this->to_ulong();
    }

    // Slice Bit Range
    unsigned long slice(unsigned L, unsigned R)
    {
        unsigned long P1;
        unsigned long P2;

        if (L>R) {
            P2 = L;
            P1 = R;
        }
        else {
            P2 = R;
            P1 = L;
        }

        unsigned long x = this->to_ulong();
        unsigned long W = P2 - P1 + 1;

        unsigned long Value = (x >> P1) & ((1<<W) - 1);

        return Value;
    }

    // Return Hex String
    string hstr() {
        stringstream xx;
        xx << "0x" << hex << this->to_ulong();
        return xx.str();
    }
};

int main(int argc, char** argv) {
    // Implicit conversion...
    unsigned long xxx = bits<4>("0101");
    unsigned long yyy = bits<4>(xxx).slice(1, 2);
}
Bimo
  • 5,987
  • 2
  • 39
  • 61