2012-09-05 128 views
0

我目前正在尝试编写一些灵活的编译时数学库,并刚刚遇到替代失败,我无法摆脱。这是问题:替换失败

首先,我正在写一个理性的类,我会把唯一需要的部分。

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 ++会选择与两个有理数一起工作的第一个模板函数,并且可以。但是,它似乎仍然尝试应用最后两个函数,并在尝试这样做时失败。我无法理解。一些帮助将受到欢迎:)

编辑:似乎具有rational构造explicit解决问题,这是伟大的。不过,我仍然很想知道替代失败的原因。

+0

也许你试图添加一个int到基于模板的变量,它不能解决冲突?你有一个operator +,它的一边是smath :: rational,另一边是int?相反呢?由于您使用的是重载的“+”运算符,因此请将每个“a + b”的情况视为对所述运算符的调用,并相应地验证类型。 – Ghost2

+0

我的'operator +'函数采用两个有理数或一个有理数的整数值(无论哪种整数类型)。有一个用于右侧的整数值,另一个用于左侧的整数值。当我给出一个有理数和一个整数值时,这些断言很有效。它只是失败了两个有理数。 – Morwenn

回答

1

问题是传递给std::enable_if<whatever, T>的类型。尽管替代会失败,但论点应该是合理的,但事实并非如此。因此,如果潜在评估类型不存在此类型,则使用typename std::common_type<T, U>::type不起作用。你需要别的东西。什么工作是创建替换故障禁止在模板参数列表中的混合整数/理性重载:

template<typename T, typename U, typename = typename std::enable_if<std::is_integral<U>::value, void>::type> 
constexpr 
rational<typename std::common_type<T, U>::type> 
operator+(const rational<T>& lhs, const U& rhs); 

template<typename T, typename U, typename = typename std::enable_if<std::is_integral<T>::value, void>::type> 
constexpr 
rational<typename std::common_type<T, U>::type> 
operator+(const T& lhs, const rational<U> rhs); 

现在我不能完全肯定,如果这是一个变通的gcc的问题,或者如果它必须这样做。

+0

谢谢,你一直在帮助很大!我仍然不知道模板的所有技巧,所以也没有想到在模板声明中放置'std :: enable_if'的权利。尽管如此,我无法告诉你是否是gcc *特定的问题。再次感谢! – Morwenn