Home > other >  How to overload function based on instance's template type
How to overload function based on instance's template type

Time:07-08

(i don't think it's a duplicate of Template member function specialization of a templated class without specifying the class template parameter reading it was a bit difficult, so i might be wrong. i also found no other possibly relevant questions)

is there a way to overload functions based on the instances template type?

in my case, i have a number class that implements a modulo operator

template <typename X>
class Operand
{
private:
        X _val;
public:
        Operand *operator% (const Operand &other_number ) const
    {
       //here, i would like use fmod for floats and doubles, and % for integers
    }
];

of course, there's always the solution of casting everything into long doubles, using fmod, and casting back into X, but it feels

  • terribly inefficient
  • Very awkward
  • not very idiomatic to C
  • and probably pretty problem prone somehow

CodePudding user response:

Since C 17, using if constexpr is very practical. Though, if you have many differences you may want to separate the floating point implementation from the integral type implementation completely.

One way of doing it would be to use the CRTP:

#include <type_traits>

template<class, bool> struct impl;

template<template<class> class O, class X>
struct impl<O<X>, true> { // specialization for floating points
    // implement all special functions for floating points here:
    O<X>* operator%(const O<X>& other) const {
        auto This = static_cast<const O<X>*>(this);
        auto v = std::fmod(This->val, other.val);
        // ...
    }
};

template<template<class> class O, class X>
struct impl<O<X>, false> { // specialization for integral types
    // implement all special functions for integral types here:
    O<X>* operator%(const O<X>& other) const {
        auto This = static_cast<const O<X>*>(this);
        auto v = This->val % other.val;
        // ...
    }
};

template <class X, std::enable_if_t<std::is_arithmetic_v<X>, int> = 0>
class Operand : public impl<Operand<X>, std::is_floating_point_v<X>> {
private:
    using impl_type = impl<Operand<X>, std::is_floating_point_v<X>>;
    friend  impl_type;
    X val;
public:
    // implement functions common to integral and floating point types here
};

CodePudding user response:

Are you looking for something like this?

if constexpr (std::is_same_v<int, X>) {
    // use %
} else if constexpr (std::is_same_v<double, X> || std::is_same_v<float, X>) {
    // use fmod
} else {
    static_assert(!std::is_same_v<int, X>
               && !std::is_same_v<double, X>
               && !std::is_same_v<float, X>,
            "Unsupported type");
}

Ugly solution, but maybe it's what you're looking for. I mean, if the number of cases is not gonna change, then it's probably ok.

However, I would question the overall design and look for topics like CPO.

  • Related