lundi 27 novembre 2017

constructor with std::pair as argument: T a({1,2}) works, T a = {1,2} doesn't

I needed big integers for a combinatorics algorithm I'm working on, and as an exercise I thought I'd write a simple 128-bit integer class, but I'm running into some inconsistencies with the constructors.

I have several constructors, so that you can create a uint128_t from another one (with the implicit copy constructor) or from a 64-bit integer or from a pair of 64-bit integers. This all works, but what's confusing me is that I can use this syntax:

uint128_t a = 123ull;
uint128_t b = a;

but not:

uint128_t e = {123ull, 456ull};               // COMPILER ERROR
uint128_t f = std::make_pair(123ull, 456ull); // COMPILER ERROR

even though these work:

uint128_t c({123ull, 456ull});
uint128_t d(std::make_pair(123ull, 456ull));

The errors I'm getting are:

could not convert '{123, 345}' from '<brace-enclosed initializer list>' to 'uint128_t'
conversion from 'std::pair<long long unsigned int, long long unsigned int>' to non-scalar type 'uint128_t' requested

I could just use the syntax that works, but I'm wondering whether there's something simple I'm missing that would get the uint128_t a = {1,2} syntax to work, because that would make it easier to convert existing code to work with 128-bit integers.

Here is an overview of what works and what doesn't, and the relevant parts of the class:

#include "uint128_t.hpp"

int main() {
    uint128_t a = 123ull;               // explixit constructor from uint64_t = ok
    uint128_t b = a;                    // implicit copy constructor = ok
    a = b;                              // assignment from uint128_t = ok
    b = 123ull;                         // assignment from uint64_t = ok
    a = {123ull, 456ull};               // assignment from pair of uint64_t = ok
    b = std::make_pair(123ull, 456ull); // assignment from pair of uint64_t = ok
    uint128_t c({123ull, 456ull});      // explixit constructor from pair = ok
    uint128_t d(std::make_pair(123ull, 456ull));

    uint128_t e = {123ull, 456ull};               // COMPILER ERROR
    uint128_t f = std::make_pair(123ull, 456ull); // COMPILER ERROR

    return 0;
}

#include <cstdint>

class uint128_t {
    private:

    uint64_t hi;
    uint64_t lo;

    public:

    uint128_t() {}
   ~uint128_t() {}
    uint128_t(uint64_t const& val) {
        hi = UINT64_C(0);
        lo = val;
    }
    uint128_t(std::pair<uint64_t const, uint64_t const> const& val) {
        hi = val.first;
        lo = val.second;
    }
    uint128_t const& operator=(uint128_t const&);
    uint128_t const& operator=(uint64_t const);
    uint128_t const& operator=(std::pair<uint64_t const, uint64_t const> const&);
}        

#include "uint128_t.hpp"

uint128_t const& uint128_t::operator=(uint128_t  const& other) {
    this->hi = other.hi;
    this->lo = other.lo;
    return *this;
}

uint128_t const& uint128_t::operator=(uint64_t const val) {
    this->hi = UINT64_C(0);
    this->lo = val;
    return *this;
}

uint128_t const& uint128_t::operator=(std::pair<uint64_t const, uint64_t const> const& val) {
    this->hi = val.first;
    this->lo = val.second;
    return *this;
}

Aucun commentaire:

Enregistrer un commentaire