2008-10-16 6 views
3

무작위 질문의 종류 ...클래스 연산자로만 캐스트 할 수있는 방법은 무엇입니까?

내가 찾고있는 것은 내가 캐스팅하는 클래스 인스턴스의 정의 된 연산자를 사용하는 캐스트 연산을 표현하고 컴파일 타임 오류를 생성합니다. 유형에 대해 정의 된 형변환 연산자가없는 경우.

template< typename RESULT_TYPE, typename INPUT_TYPE > 
RESULT_TYPE operator_cast(const INPUT_TYPE& tValue) 
{ 
    return tValue.operator RESULT_TYPE(); 
} 

// Should work... 
CString sString; 
LPCTSTR pcszString = operator_cast<LPCTSTR>(sString); 

// Should fail... 
int iValue = 42; 
DWORD dwValue = operator_cast<DWORD>(iValue); 

재미있는 측면 참고 : 그래서, 예를 들어, 내가 무엇을 찾고있어 같은입니다 위의 코드는 VS2005 C++ 컴파일러를 충돌, 인해에 VS2008 C++ 컴파일러에서 제대로 컴파일되지 않는 것 나는 컴파일러 버그라고 생각하지만, 그 아이디어를 잘 보여줄 것이다.

아무도이 효과를 얻으려면 어떤 방법을 알고 있습니까?

편집 : 이유가 무엇인지 설명해주십시오. 형식을 캡슐화하거나 추상화해야하는 래퍼 클래스가 있고이를 캡슐화 된 형식으로 캐스팅한다고 가정합니다. static_cast <>을 사용할 수는 있지만 실패 (예 : 컴파일러가 요청한 유형으로 변환 할 수있는 연산자를 선택합니다. 연산자가 없기 때문에 오류를 원할 때).

틀림없이 그렇긴하지만 필자가 컴파일러에서 캡슐화 된 함수로 수행하고자하는 것을 정확히 표현할 수 없다는 것은 짜증 스럽다.

답변

3

코드는 (보통은 ++ 유효한 C 있다는 좋은 지표 임) Cameau compiler와 작품을 기록했다.

유효한 캐스트는 하나 이상의 사용자 정의 캐스트로 구성되어 있으므로 가능한 다른 솔루션은 캐스팅 템플릿에 새 형식을 정의하고 캐스트가없는 static assert을 갖는 다른 사용자 정의 캐스트를 추가하는 것입니다 는 새로운 유형에서 결과 유형 (boost is_convertible 사용)까지 사용할 수 있지만 캐스트 연산자와 캐스트 생성자 (하나의 인수로 ctor)를 구별하지 않으며 추가 캐스트가 발생하도록합니다 (예 : 에서 bool까지). 캐스트 연산자와 캐스트 생성자를 구별하는 것이 올바른 경우 할 일이 있는지는 잘 모르겠지만 그게 문제입니다.

이 문제를 해결하기 위해 며칠이 지나면 캐스팅 운영자의 주소를 간단히 가져올 수 있습니다. 이것은 멤버 구문에 대한 C++의 털이 포인터로 인해 수행되는 것보다 약간 더 쉽습니다 (올바른 결과를 얻으려면 예상보다 오래 걸렸습니다). VS2008에서 작동하는지 모르겠다. Cameau에서만 확인했다.

template< typename Res, typename T> 
Res operator_cast(const T& t) 
{ 
    typedef Res (T::*cast_op_t)() const; 
    cast_op_t cast_op = &T::operator Res; 
    return (t.*cast_op)(); 
} 

편집

: 내가 VS2005와 VS2008에서 테스트 할 수있는 기회를 얻었다. 내 발견은 원래의 포스터와 다릅니다.

  • VS2008에서 원본 버전이 제대로 작동하는 것 같습니다.
  • VS2005에서 원본 버전은 빌트인 형식 (예 : int에서 int로 캐스팅)에서 캐스팅 할 때만 컴파일러가 작동하지 않으므로 컴파일 오류가 발생하므로 컴파일 오류가 발생합니다. 컴파일 오류가 발생해도 모든 경우에 작동합니다.
+0

두 가지 예를 들어 템플릿을 사용해 보았습니까? VS2008은 템플릿 자체를 컴파일해도 잘 작동 할 것입니다. – Nick

+0

방금 ​​해 보았는데 솔루션이 잘 작동하는 것 같습니다. 내가 VS2005에 내장 된 형식에 대한 초기 typedef에 대한 컴파일러 오류가 발생했습니다. 좋은 생각. :) – Nick

1

explicit으로 표시된 변환 생성자를 사용하면 컴파일러가 암시 적으로 변환 된 형식에서 래퍼 클래스를 초기화하지 못하도록 방지 할 수 있습니다.

/* general template */ 
template<typename T1, typename T2> T1 operator_cast(const T2 &x); 

/* do this for each valid cast */ 
template<> LPCTSTR operator_cast(const CString &x) { return (LPCTSTR)x; } 

편집 : 다른 게시물에 언급 한 바와 같이, 당신은 당신에게 경우에 더 유용한 오류 메시지가 제공하는 일반 버전에서 뭔가를 넣을 수 있습니다

+0

예,하지만 명시 적 생성자를 추가하거나 변환 비헤이비어를 수정할 수없는 기본 제공 내장 유형으로 캐스팅하는 것은 어떻습니까? – Nick

+0

두 개의 내장 유형 사이의 기본 전송 동작을 변경 하시겠습니까? –

+0

아니요, 래퍼 클래스에서 내장 형식으로 변환 중이므로 컴파일러에서 내장 형식을 명시 적으로 만 생성하도록 지정할 수는 없습니다 (일반적인 의미에서도 잘못 될 수 있음). – Nick

0

는 전문성을 템플릿을 원하는 것처럼,이 같은 것을 할 것입니다 소리 지원되지 않는 캐스트가 수행됩니다.

1

템플릿 관련 컴파일러 오류 메시지는 일반적으로 해결하기가 어려우므로 각 변환을 지정하는 것을 신경 쓰지 않으면 컴파일러에서 기본 템플릿 정의를 제공하여 실패 사례에서 더 유용한 메시지를 내보낼 수 있습니다 . 이것은 컴파일러가 실제로 호출 된 템플릿의 코드 만 컴파일하려고 시도한다는 사실을 사용합니다.

#include <string> 

// Class to trigger compiler warning 
class NO_OPERATOR_CONVERSION_AVAILABLE 
{ 
private: 
    NO_OPERATOR_CONVERSION_AVAILABLE(){}; 
}; 

// Default template definition to cause compiler error 
template<typename T1, typename T2> T1 operator_cast(const T2&) 
{ 
    NO_OPERATOR_CONVERSION_AVAILABLE a; 
    return T1(); 
} 

// Template specialisation 
template<> std::string operator_cast(const std::string &x) 
{ 
    return x; 
} 
+0

더 유용한 오류를 얻는 멋진 기술. –

+0

일반 버전을 작성하는 대신 각 "유효한"케이스를 명시 적으로 정의해야하는 단점이 있습니다. 효과를 더 잘 포착하려면이 버전을 allowed_cast라고 부릅니다. – Nick

+0

예, 의미 론적 차이가 유효하다고 생각합니다. 명시 적 변환 연산자가 적용되는지 여부를 컴파일 타임에 결정할 수있는 방법이 있어야합니다. * 모든 변환이 유효한지 어떻게 알 수 있는지 생각할 수 있지만 명시 적으로 어렵습니다. 좀 더 생각할 것입니다 ... – user23167