Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Specialisation of std::hash with template parameters

I have the following templated data structure

#include <cinttypes>
#include <cfloat>
#include <type_traits>
#include <algorithm>

constexpr bool is_base_2(uint64_t number){
    return (number != 1) && ((number & (number - 1)) == 0);
}

constexpr uint64_t power(uint64_t number, uint8_t index){
    uint64_t current{number};
    for(uint8_t i{1}; i <= index; i++){
        current *= number;
    }
    return current;
}



// implementation details: https://en.wikipedia.org/wiki/Fixed-point_arithmetic
template <
        std::size_t size,
        uint64_t scaling_factor_inverse,
        bool is_signed = true,
        typename = typename std::enable_if_t<is_base_2(scaling_factor_inverse)>,
        typename UnderlyingIntegerType =
            typename std::conditional_t<(size == 16) && is_signed,
                std::int16_t,
            typename std::conditional_t<(size == 16) && !is_signed,
                std::uint16_t,
            typename std::conditional_t<(size == 32) && is_signed,
                std::int32_t,
            typename std::conditional_t<(size == 32) && !is_signed,
                std::uint32_t,
            typename std::conditional_t<(size == 64) && is_signed,
                std::int64_t,
            typename std::conditional_t<(size == 64) && !is_signed,
                std::uint64_t,
                void
            >>>>>
        >
>
class fixed{

friend struct std::hash<fixed<size, scaling_factor_inverse, is_signed>>;

public:

    template <
            typename Number,
            typename std::enable_if_t<std::is_arithmetic_v<Number> , int> = 0>
    fixed(const Number& number){
        static_assert(
            std::is_signed_v<Number> ? is_signed : true,
            "cannot create unsigned fixed-point from signed arithmetic type"
        );
        data = number * scaling_factor_inverse;
    }

    fixed( const fixed & ) = default;

    template<
        typename Number,
        typename = typename std::enable_if_t<std::is_arithmetic_v<Number>>
    >
    operator Number() const
    {
        static_assert(
            std::is_unsigned_v<Number> ? !is_signed : true,
            "cannot convert signed fixed-point to an unsigned arithmetic type"
        );
        return
        static_cast<Number>(
            static_cast<long double>(data) /
            static_cast<UnderlyingIntegerType>(scaling_factor_inverse)
        )
        ;
    }


private:

    UnderlyingIntegerType data;
    fixed() = default;

};

template<std::size_t Size, uint64_t ScalingFactorInverse, bool Signed>
struct std::hash<fixed<Size, ScalingFactorInverse, Signed>>{
        std::size_t operator()(fixed<Size, ScalingFactorInverse, Signed> number) const {
        static std::hash<decltype(number.data)> hasher{};
        return hasher(number.data);
    }
};

I am trying to create a specialisation of std::hash for this class as follows

template<std::size_t Size, uint64_t ScalingFactorInverse, bool Signed>
struct std::hash<fixed<Size, ScalingFactorInverse, Signed>>{
        std::size_t operator()(fixed<Size, ScalingFactorInverse, Signed> number) const {
        static std::hash<decltype(number.data)> hasher{};
        return hasher(number.data);
    }
};

but I am receiving a the compilation error

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

error: expected parameter declarator
        std::size_t operator()(fixed<Size, ScalingFactorInverse, Signed> number) const {
                               ^
 src/main/util/fixed_point.h:181:74: error: expected ')'
        std::size_t operator()(fixed<Size, ScalingFactorInverse, Signed> number) const {
                                                                         ^

I have been unable to determine the cause of this issue, I would be grateful if someone could point me in the right direction.

Please be gentle with me.

I have tried to replace

    std::size_t operator()(fixed<Size, ScalingFactorInverse, Signed> number) const {

but I think this may cause issues somewhere else (I’m not sure?).

>Solution :

You need to add :: to fixed in the operator() or else it may pick up std::fixed which is a function in the std namespace (which is where your specialization lives):

template<std::size_t Size, uint64_t ScalingFactorInverse, bool Signed>
struct std::hash<fixed<Size, ScalingFactorInverse, Signed>>{
    std::size_t operator()(::fixed<Size, ScalingFactorInverse, Signed> number) const {
//                             ^^
        static std::hash<decltype(number.data)> hasher{};
        return hasher(number.data);
    }
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading