Член класса шаблонов против неоднозначности функции-члена
Я разрабатываю библиотеку только для заголовков для автоматического / алгоритмического дифференцирования. Цель состоит в том, чтобы иметь возможность просто изменить тип переменных, передаваемых в функцию, и вычислить первую и вторую производные. Для этого я создал шаблонный класс, который позволяет программисту выбирать тип хранилища для закрытых членов данных. Ниже приведен фрагмент с перегрузкой оператора-нарушителя.
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;
};
Позже, чтобы максимизировать универсальность, я предоставляю шаблонные функции для обеспечения взаимодействия.
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]);
}
Я сталкиваюсь с тем, что компилятор пытается создать вторую функцию-член, не являющуюся членом.
#include "hyperspace.h"
int main()
{
HyperDual<long double> one(1); // There is an appropriate constructor
HyperDual<double> two(2);
one + two;
return 0;
}
Я получаю сгенерированную static_assert ошибку "LHS должен быть числовым" для этого. Как бы я решил эту двусмысленность?
2 ответа
Хорошо. Я нашел свою проблему. Это сводится к разнице между static_assert и std::enable_if
Заменив объявление шаблона и удалив static_assert, я достигну эквивалентной функциональности:
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());
}
(Маленькая деталь, но rhs.values[0]
был заменен на rhs.value()
, Это не имело ничего общего с проблемой шаблона, но было связано с доступом пользователей.
Использование enable_if_t
сделать не-членский шаблон можно применять только в конкретном контексте?
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);
}
static_assert
может быть продублировано здесь.