Give an aggregate a converting constructor?

198 views Asked by At

I'm writing a large fixed-size integer type that is made up of multiple uint64_ts, like in the (simplified) example below. I would like my type to behave like the built-in integer types, which means (among other things) that:

  1. it should be uninitialized if you don't assign a value to it, and
  2. it should accept widening from other built-in integer types.

It appears to me, however, that one cannot write a type that simultaneously satisfies both properties. This is because property 1 requires the type to be an aggregate, which means it must have no constructors, and we need a constructor to implement property 2.

Is there any way to write a large integer type that satisfies both properties?

#include <array>
#include <cstdint>

struct uint128_t{
    std::array<uint64_t, 2> data;
};

int main(){
    uint128_t x; // uninitialized (good)
    uint128_t y = 100; // can we make this work while ensuring that the previous line still works?
}
2

There are 2 answers

0
HolyBlackCat On BEST ANSWER

A constructor such as uint128_t() {} will leave your array uninitialized by default. Ability to leave members uninitalized has nothing to do with being an aggregate.

But there's a better option: uint128() = default;. It will cause uint128_t x; to be uninitialized, but uint128_t x{}; will be zeroed, just like with built-in types.

0
aleck099 On

This is because property 1 requires the type to be an aggregate, which means it must have no constructors

No, it could have empty constructors

class uint128_t{
public:
    // this is an empty constructor, it does not initializes data
    uint128_t() {}; 
    // calling this ctor will create an object with an initial value "val"
    uint128_t(uint64_t val)
        :data{0, val} {}
    // for larger numbers
    uint128_t(std::string_view src) {
        // implement it yourself
    }
private:
    std::array<uint64_t, 2> data;
};