문제

산술을 캡슐화하는 클래스가 있습니다. 고정점 계산이라고 가정 해 봅시다. 산술 연산자 과부하라는 아이디어가 마음에 들기 때문에 다음을 작성합니다.

class CFixed
{
   CFixed( int   );
   CFixed( float );
};

CFixed operator* ( const CFixed& a, const CFixed& b )
{ ... }

그것은 모두 작동합니다. 3 * cfixed (0) 및 cfixed (3) * 10.0f를 쓸 수 있습니다. 그러나 이제는 정수 피연산자가 훨씬 효과적으로 운영자*를 구현할 수 있습니다. 그래서 나는 그것을 과부하합니다.

CFixed operator* ( const CFixed& a, int b )
{ ... }
CFixed operator* ( int a, const CFixed& b )
{ ... }

여전히 작동하지만 이제 Cfixed (0) * 10.0f 호출 오버로드 된 버전으로 float를 int로 변환합니다 (그리고 float를 cfixed로 변환 할 것으로 예상). 물론, 플로트 버전도 과부하 할 수 있지만 코드의 조합 폭발로 보입니다. 해결 방법이 있습니까 (아니면 수업을 잘못 설계하고 있습니까?)? Compiler에 오버로드 된 버전의 연산자*를 ints로만 호출하도록하려면 어떻게해야합니까?

도움이 되었습니까?

해결책

전문화 된 버전을 모든 적분 유형에 대해 선택하려고한다고 가정합니다 (뿐만 아니라 int 특히, 당신이 할 수있는 한 가지는 템플릿 함수로서 Boost.enableif를 사용하여 피연산자가 적분 유형이 아닌 경우 사용 가능한 오버로드 세트에서 해당 오버로드를 제거하는 것입니다.

#include <cstdio>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

class CFixed
{
public:
   CFixed( int   ) {}
   CFixed( float ) {}
};

CFixed operator* ( const CFixed& a, const CFixed&  )
{ puts("General CFixed * CFixed"); return a; }

template <class T>
typename boost::enable_if<boost::is_integral<T>, CFixed>::type operator* ( const CFixed& a, T  )
{ puts("CFixed * [integer type]"); return a; }

template <class T>
typename boost::enable_if<boost::is_integral<T>, CFixed>::type operator* ( T , const CFixed& b )
{ puts("[integer type] * CFixed"); return b; }


int main()
{
    CFixed(0) * 10.0f;
    5 * CFixed(20.4f);
    3.2f * CFixed(10);
    CFixed(1) * 100u;
}

당연히 다른 조건을 사용하여 T = int 인 경우에만 오버로드를 사용할 수 있습니다. typename boost::enable_if<boost::is_same<T, int>, CFixed>::type ...

클래스 설계에 관해서는 아마도 템플릿에 더 의존 할 수 있습니다. 예를 들어, 생성자는 템플릿이 될 수 있으며, 통합 유형과 실제 유형을 구별 해야하는 경우이 기술을 사용하는 것이 가능해야합니다.

다른 팁

당신은 과부하해야합니다 float 또한 입력하십시오. 전환 int 사용자 지정 유형 (CFixed) 내장 플로팅 통신 변환보다 우선 순위가 낮습니다. float. 따라서 컴파일러는 항상 기능을 선택합니다 int, 기능을 추가하지 않는 한 float 또한.

자세한 내용은 C ++ 03 표준의 13.3 섹션을 참조하십시오. 고통을 느끼다.

나도 추적을 잃어버린 것 같습니다. :-( 벤 삼촌의 플로트를 추가하는 것은 문제를 버전으로 해결하는 것이 아니라는보고 double 추가해야합니다. 그러나 어쨌든 내장 유형과 관련된 여러 연산자를 추가하는 것은 지루하지만 조합 부스트는 아닙니다.

하나의 인수만으로 호출 할 수있는 생성자가있는 경우 효과적으로 암시 적 변환 연산자를 만들었습니다. 당신의 예에서, 어디서나 CFixed 둘 다 필요하다 int 그리고 a float 통과 할 수 있습니다. 컴파일러가 일부 기능 선언을 포함하는 것을 잊어 버릴 때 짖는 대신 잘못된 함수를 호출하는 코드를 조용히 생성 할 수 있기 때문에 이것은 위험합니다.

따라서 좋은 경험 법칙에 따르면, 당신이 하나의 주장만으로 부를 수있는 생성자를 작성할 때마다 foo(int i, bool b = false) 하나의 인수로 호출 할 수 있습니다. explicit, 실제로 암시 적 변환이 시작되기를 원하지 않는 한. explicit 생성자는 컴파일러에서 암시 적 변환을 위해 사용하지 않습니다.

수업을 이것으로 바꿔야합니다.

class CFixed
{
   explicit CFixed( int   );
   explicit CFixed( float );
};

나는이 규칙에 예외가 거의 없다는 것을 알았다. (std::string::string(const char*) 다소 유명한 사람입니다.)

편집하다: 미안 해요 int 에게 float.

이것을 방지하는 유일한 방법은 운영자에게 float 또한.

변환을 만드는 것은 어떻습니까 명백한?

SBI에 동의하면 단일 파라미터 생성자를 명시 적으로 만들어야합니다.

그러나 템플릿으로 작성한 연산자 <> 기능의 폭발을 피할 수 있습니다.

template <class T>
CFixed operator* ( const CFixed& a, T b ) 
{ ... } 

template <class T>
CFixed operator* ( T a, const CFixed& b ) 
{ ... } 

함수의 코드에 따라 변환을 지원하는 유형과 만 컴파일됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top