calccrypto
calccrypto

Reputation: 8991

Selecting the right equality operator when using templates

im trying to write a uint128_t library (http://stackoverflow.com/questions/6119306/operator-overloading-c-placement) and ive hit a bump: i need to operate on different types of ints, such as uint128_t ^ uint64_t. i have written the operator overloads such as template <typename t> uint128_t operator^(T val). i also need to be able to do uint128_t ^ uint128_t. however, since my uint128_t uses 2 uint64_t s to store the values, i cant simply use uint128_t as T. thus, i have written 2 different functions, one with T as the argument type and the other with uint128_t as the type.

the problem is that the compiler is using the T val version for both standard c++ int types and uint128_t. how do i get the compiler to differentiate between them?

edit: i have this code in the class in the link:

template <typename T>
bool operator==(T val){
    return (LOWER == (uint64_t) val);
}

bool operator==(uint128_t val){
    return ((UPPER == val.upper()) && (LOWER == val.lower()));
}

if i do

uint128_t a(5), b(123, 45);
uint64_t c = 6;

(a == c);
(a == b);

both lines would use the top operator. however, since uint128_t is 2 parts, and is an object, the computer will be comparing a uint64_t to a class, not to a value. how do i force the computer to use the second == operator?

Upvotes: 1

Views: 306

Answers (2)

fileoffset
fileoffset

Reputation: 976

Try taking the template operators out of the class and making them global, then specifying the specific conversions you need, i.e:

template<typename T>
bool operator==(uint128_t v1, T v2)
{
    return (v1.lower() == (uint64_t) v2);
}

template<>
bool operator==(uint128_t v1, uint128_t v2)
{
    return ((v1.upper() == v2.upper()) && (v1.lower() == v2.lower()));
}

Upvotes: 1

Benjamin Lindley
Benjamin Lindley

Reputation: 103693

You shouldn't even need the extra overloads for anything other than the conversion constructors. Then you just write the operators that handle uint128_t, and if you try to pass another convertible type, such as an int, it will be converted using the conversion constructor, then the appropriate operator will be called.

See, this works:

#include <cstdint>
#include <iostream>

class uint128_t{
    private:
        uint64_t UPPER, LOWER;

    public:
    // constructors
        uint128_t(){
            UPPER = 0;
            LOWER = 0;
        }

        template <typename T>
        uint128_t(T val){
            UPPER = 0;
            LOWER = (uint64_t) val;
        }

        template <typename S, typename T>
        uint128_t(const S & upper_val, const T & lower_val){
            UPPER = (uint64_t) upper_val;
            LOWER = (uint64_t) lower_val;
        }       

        uint64_t upper() const{
            return UPPER;
        }

        uint64_t lower() const{
            return LOWER;
        }

        uint128_t & operator+=(const uint128_t & rhs)
        {
            uint64_t old_lower = LOWER;
            LOWER += rhs.LOWER;
            if(LOWER < old_lower)
                ++UPPER;
            UPPER += rhs.UPPER;
            return *this;
        }
};

bool operator==(const uint128_t & lhs, const uint128_t & rhs){
    return ((lhs.upper() == rhs.upper()) && (lhs.lower() == rhs.lower()));
}

int main()
{
    uint128_t v(25);
    v += 25;
    int c = 50;
    if(v == c)
        std::cout << "Good";
    if(v == c + 1)
        std::cout << "Bad";
}

http://ideone.com/BEq03

Upvotes: 1

Related Questions