В настоящее время я пытаюсь написать некоторую гибкую математическую библиотеку времени компиляции и только что столкнулся с ошибкой замены, от которой мне не удается избавиться. Вот проблема:
Первым делом пишу рациональный класс, поставлю только ту часть, которая нужна.
template<typename T>
class rational
{
static_assert(std::is_integral<T>::value, "Can only contain integral values.");
public:
constexpr rational(T numerator, T denominator);
private:
T _numerator;
T _denominator;
};
И чтобы библиотека была гибкой, я пытался активно использовать SFINAE, чтобы ограничить вызовы операторных функций только рационально-рациональными, рационально-интегральными и интегрально-рациональными, но которые будут работать независимо от интеграла и лежащего в его основе. тип интеграла. Вот, например, объявления функций для operator+
:
template<typename T, typename U>
constexpr
rational<typename std::common_type<T, U>::type>
operator+(const rational<T>& lhs, const rational<U>& rhs);
template<typename T, typename U>
constexpr
typename std::enable_if<std::is_integral<U>::value, rational<typename std::common_type<T, U>::type>>::type
operator+(const rational<T>& lhs, const U& rhs);
template<typename T, typename U>
constexpr
typename std::enable_if<std::is_integral<T>::value, rational<typename std::common_type<T, U>::type>>::type
operator+(const T& lhs, const rational<U> rhs);
А вот и ошибочный сегмент кода. Он падает не из-за static_assert
, а предположительно из-за ошибки подстановки:
constexpr auto r1 = rational<int>(1, 2);
constexpr auto r2 = rational<int>(2, 4);
static_assert(r1 + r2 == rational<int>(1, 1), "");
Ошибка следующая (у меня сохранились только ошибки без окружающего блабла):
... required by substitution of 'template<class T, class U> constexpr typename std::enable_if<std::is_integral<T>::value, smath::rational<typename std::common_type<_Tp, _Up>::type> >::type smath::operator+(const T&, smath::rational<U>) [with T = smath::rational<int>; U = int]'
... required from here
... error: operands to ?: have different types 'smath::rational<int>' and 'int'
... required by substitution of 'template<class T, class U> constexpr typename std::enable_if<std::is_integral<U>::value, smath::rational<typename std::common_type<_Tp, _Up>::type> >::type smath::operator+(const smath::rational<T>&, const U&) [with T = int; U = smath::rational<int>]'
... required from here
... error: operands to ?: have different types 'int' and 'smath::rational<int>'
Я предполагаю, что g++ выберет первую шаблонную функцию, которая работает с двумя рациональными числами, и с ней все будет в порядке. Однако кажется, что он все еще пытается применить последние две функции и терпит неудачу при попытке сделать это. Что я не могу понять. Некоторая помощь будет приветствоваться :)
EDIT: кажется, что наличие конструктора rational
explicit
решает проблему, и это здорово. Тем не менее, мне все еще интересно узнать, почему замена так сильно провалилась.
operator+
принимают два рациональных числа или целочисленное рациональное число (в зависимости от того, какой целочисленный тип). Один для интегрального значения справа и один для интегрального значения с левой стороны. Утверждения хорошо работают, когда я даю рациональное число и целочисленное значение. Это просто терпит неудачу с двумя рациональными числами. - person Morwenn   schedule 06.09.2012