我目前正在尝试编写一些灵活的编译时数学库,但遇到了我无法摆脱的替换失败。这是问题所在:
首先,我正在写一个理性类,我会放唯一需要的部分。
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), "");
错误如下(我只保留了没有周围blabla的错误):
... 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++ 会选择第一个使用两个有理数的模板函数并且可以接受。但是,它似乎仍然尝试应用最后两个功能并且在尝试这样做时失败了。我无法理解。一些帮助将受到欢迎:)
编辑:似乎让rational
构造函数explicit
解决了这个问题,这很好。但是,我仍然有兴趣知道为什么替换失败了。