2012-09-05 183 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