2012-09-03 7 views
4

Google Test (gtest) 코드를 VxWorks 5.5로 이식하려고합니다. 심각한 단점은 개발 환경 Tornado 2.2가 고대 GCC 컴파일러 버전 2.96을 사용한다는 것입니다.이 C++ 템플릿 클래스 코드는 어떻게 작동합니까?

코드의 일부분을 찾아 냈는데 gtest.h 코드 부분에 있습니다. 이해가 안됩니다! 이 C++ 템플릿 클래스는 어떻게 작동합니까? 이 클래스의 객체가 생성 될 때 템플릿 유형 From이 템플릿 유형 To에 암시 적으로 변환하는 경우

// ImplicitlyConvertible<From, To>::value is a compile-time bool 
// constant that's true iff type From can be implicitly converted to 
// type To. 
template <typename From, typename To> 
class ImplicitlyConvertible { 
private: 
    // We need the following helper functions only for their types. 
    // They have no implementations. 

    // MakeFrom() is an expression whose type is From. We cannot simply 
    // use From(), as the type From may not have a public default 
    // constructor. 
    static From MakeFrom(); 

    // These two functions are overloaded. Given an expression 
    // Helper(x), the compiler will pick the first version if x can be 
    // implicitly converted to type To; otherwise it will pick the 
    // second version. 
    // 
    // The first version returns a value of size 1, and the second 
    // version returns a value of size 2. Therefore, by checking the 
    // size of Helper(x), which can be done at compile time, we can tell 
    // which version of Helper() is used, and hence whether x can be 
    // implicitly converted to type To. 
    static char Helper(To); 
    static char (&Helper(...))[2]; // NOLINT 

    // We have to put the 'public' section after the 'private' section, 
    // or MSVC refuses to compile the code. 
public: 
    // MSVC warns about implicitly converting from double to int for 
    // possible loss of data, so we need to temporarily disable the 
    // warning. 
#ifdef _MSC_VER 
# pragma warning(push)   // Saves the current warning state. 
# pragma warning(disable:4244) // Temporarily disables warning 4244. 

    static const bool value = 
     sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; 
# pragma warning(pop)   // Restores the warning state. 
#elif defined(__BORLANDC__) 
    // C++Builder cannot use member overload resolution during template 
    // instantiation. The simplest workaround is to use its C++0x type traits 
    // functions (C++Builder 2009 and above only). 
    static const bool value = __is_convertible(From, To); 
#else 
    static const bool value = 
     sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; 
#endif // _MSV_VER 
}; 

는 이름 value와 부울 변수는 답을 포함해야합니다. 대답을 얻으려면 MakeFrom()Helper()의 두 가지 전용 함수가 사용됩니다. 그러나이 두 함수는 여기서 선언 할 뿐이며, 둘 중 어느 것에 대해서도 정의를 찾을 수 없습니다. 그 밖의 것이 없다면이 구현은 연결되지 않아야합니다.

이 나도는 물론 다음

static char (&Helper(...))[2]; 

의 구문을 이해하지 않는,이 코드는 잘 컴파일합니다 (아래의 Microsoft Visual C++ 7.1 이상 또는 GCC 3.4 이상)와 구글의 사람들은 정확히 무엇을 알고 그들이 하고있다.

제발 저를 계몽하십시오! 이 코드를 이해하지 못하면 나를 미쳐 버릴 수 있습니다! :)

답변

10

이것은 템플릿 프로그래밍의 표준 트릭입니다. 코멘트가

참고 "도우미의 크기를 확인하여 (x)는" :이 코드가 Helper으로 수행하는 것은 일부 x에 대한 sizeof(Helper(x))을 평가하는 것을 강조한다. sizeof 연산자 은 실제로는 인수을 평가하지 않습니다 (필요한 것은 아니며 컴파일시 사용할 수있는 정보 만 사용하여 찾을 수 있습니다) 이는 링커 오류가없는 이유입니다 (Helper은 절대로 호출되지 않습니다.)

문제를 일으키는 구문은 Helper이 숫자와 유형의 매개 변수를 허용하고 char[2]에 대한 참조를 반환하는 기능임을 의미합니다. 이 유형의 함수 (variadic function)에 대한 서명을 작성하려면 마지막 인수에 대한 지정으로 줄임표 (...)를 사용해야합니다.

Variadic 함수는 C에서 상속받은 피할 수있는 피쳐이며 클래스 유형과 함께 사용할 경우 일반적으로 피해야하지만이 경우에는 앞서 언급했듯이 Helper이 실제로 호출되지 않기 때문에 중요하지 않습니다.

당신이 value을 생산하기 위해 구문

ImplicitlyConvertible<From, To>::value 

을 사용할 수 있도록하여이 모두 함께 클래스 넥타이, 코드 "가짜"Helper를 호출하고 argument¹로에게 From의 인스턴스를 전달합니다. 이 시나리오에서는 To을 필요로하는 오버로드가 있는지 결정하기 위해 컴파일러의 오버로드 해결을 사용합니다. 그렇다면, 그 과부하의 반환 값은 1value의 보장 된 크기를 갖는 char이되고 true이된다.그렇지 않으면 임의의 유형의 인수를 사용할 수있는 가변적 인 과부하가 선택되며 char[2]을 반환합니다. 이 크기는 1보다 크므로 valuefalse으로 끝납니다.


다시 "sizeof 실제로 식을 평가하지 않습니다"트릭을 사용하는 여기에 있습니다 ¹ : 어떻게 Helper에 인수가 From의 인스턴스 인 컴파일러를 알 수 있습니까? From()을 사용할 수 있지만 From에는 컴파일 할 코드의 기본 public 생성자가 있어야합니다. 따라서 컴파일러에게 "MakeFromFrom을 반환합니다"라고 말하면 함수가 실제로 호출되지 않습니다.

관련 문제