0

I'm developing a header-only library for automatic/algorithmic differentiation. The goal is to be able to simply change the type of the variables being fed to a function and calculate first and second derivatives. For this, I've created a template class that allows the programmer to select the storage type for the private data members. Included is a snippet below with an offending operator overload.

template <typename storage_t>
class HyperDual
{
    template <typename T> friend class HyperDual;
    public:
        template <typename T>
        HyperDual<storage_t> operator+(const HyperDual<T>& rhs) const
        {
            HyperDual<storage_t> sum;
            for (size_t i = 0; i < this->values.size(); i++)
                sum.values[i] = this->values[i] + rhs.values[i];
            return sum;
        }
    protected:
        std::vector<storage_t> values;
};

Later on, to maximize the versatility, I provide template functions to allow interaction.

template <typename storage_t, typename T>
HyperDual<storage_t> operator+(const HyperDual<storage_t>& lhs, const T& rhs)
{
    static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "RHS must be numeric");
    return HyperDual<storage_t>(lhs.values[0] + rhs);
}

template <typename storage_t, typename T>
HyperDual<storage_t> operator+(const T& lhs, const HyperDual<storage_t>& rhs)
{
    static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "LHS must be numeric");
    return HyperDual<storage_t>(lhs + rhs.values[0]);
}

What I'm encountering is that the compiler is trying to instantiate the second non-member template function.

#include "hyperspace.h"

int main()
{
    HyperDual<long double> one(1); // There is an appropriate constructor
    HyperDual<double> two(2);

    one + two;

    return 0;
}

I get the static_assert generated error "LHS must be numeric" for this. How would I resolve the ambiguity?

  • 1
    You provide `operator+=`, but you never declared `operator+(HyperDual, HyperDual)`, you likely needs to declare it. `operator+=` does not give you `operator+` for free. – Holt Jan 26 '19 at 12:15
  • If both operands are `HyperDual`, presumably you should want to provide a separate `operator+`, no? – L. F. Jan 26 '19 at 12:15
  • I copied the wrong function from my code. It was supposed to be the member operator+ function. The question has been updated with the correct function. – Matt Osborne Jan 27 '19 at 01:15

2 Answers2

0

use enable_if_t to make the non-member template can only be applied in the specific context?

template <typename storage_t, typename T, typename = enable_if_t<std::is_arithmetic<T>::value && !(std::is_same<T, char>::value)>>
HyperDual<storage_t> operator+(const HyperDual<storage_t>& lhs, const T& rhs)
{
    static_assert(std::is_arithmetic<T>::value && !(std::is_same<T, char>::value), "RHS must be numeric");
    return HyperDual<storage_t>(lhs.values[0] + rhs);
}

the static_assert may be duplicated here.

user8510613
  • 1,242
  • 9
  • 27
0

Ok. I found my own issue. It comes down to the difference between static_assert and std::enable_if

Replacing my template declaration and removing static_assert, I achieve equivalent functionality:

template <typename storage_t, typename T,
          typename = typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, char>::value>::type>
HyperDual<storage_t> operator+(const T& lhs, const HyperDual<storage_t>& rhs)
{
    return HyperDual<storage_t>(lhs + rhs.value());
}

(Small detail, but rhs.values[0] was replaced with rhs.value(). This had nothing to do with the template issue, but was related to member access.