2012-09-05 2 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의 무거운 사용할 수 있도록 호출려고 만 합리적 이성하는 것 합리적 통합 및 통합 - 합리적하지만, 적분과 근본적인 유형의 적분이 무엇이든지간에 작동합니다. 여기

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); 

그리고 코드의 결함 세그먼트 : 여기에 예를 들어 operator+에 대한 함수 선언이다. 이 때문에 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을 가진 것은 대단한 문제를 해결 것으로 보인다. 그러나, 나는 대체가 왜 그렇게 열심히 실패했는지에 대해서 아직도 관심이있다.

+0

어쩌면 템플릿 기반 변수에 int를 추가하려고하는데 충돌을 해결할 수 없습니까? 한쪽에는 합리적인, 다른 한쪽에는 정수를 취하는 연산자 +가 있습니까? 그 반대는 어때? 오버로드 된 '+'연산자를 사용하고 있으므로 'a + b'의 각 사례를 상기 연산자에 대한 호출로 처리하고 이에 따라 형식을 확인하십시오. – Ghost2

+0

'operator +'함수는 두 개의 유리수 또는 유리수를 정수 값 (둘 중 하나의 정수 유형)으로 사용합니다. 오른쪽에는 정수 값을위한 값이 있고 왼쪽에는 정수 값을 나타내는 값이 있습니다. 단언은 합리적인 수와 정수 값을 줄 때 잘 작동합니다. 그것은 단지 2 개의 유리수로 실패합니다. – 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