문제

우리는 부모 프로젝트에 걸쳐 많은 일반적인 코드 스냅 펫이있는 하위 프로젝트 'Commonutils'가 있습니다. 내가 본 흥미로운 것 중 하나는 다음과 같습니다.-

/*********************************************************************
If T is polymorphic, the compiler is required to evaluate the typeid 
stuff at runtime, and answer will be true.  If T is non-polymorphic, 
the compiler is required to evaluate the typeid stuff at compile time, 
whence answer will remain false
*********************************************************************/
template <class T> 
bool isPolymorphic() { 
   bool answer=false; 
   typeid(answer=true,T()); 
   return answer; 
}

나는 그 의견을 믿었고 프로젝트에서 사용되지는 않지만 그것이 매우 흥미로운 템플릿이라고 생각했습니다. 호기심을 위해 이렇게 사용해 보았습니다 ...

class PolyBase {
public:
   virtual ~PolyBase(){}
};

class NPolyBase {
public:
   ~NPolyBase(){}
};


if (isPolymorphic<PolyBase>())
  std::cout<<"PolyBase = Polymorphic\n";
if (isPolymorphic<NPolyBase>())
  std::cout<<"NPolyBase = Also Polymorphic\n";

그러나 그 중 어느 것도 사실이 아닙니다. MSVC 2005는 경고를 제공하지 않지만 Comeau는 TypeID 표현에 영향을 미치지 않는다고 경고합니다. C ++ 표준의 섹션 5.2.8은 댓글이 말하는 것과 같은 것을 말하지 않습니다. IE TypeID가 비 폴리 흉부 유형의 컴파일 시간과 다형성 유형의 런타임에 평가됩니다.

1) 그래서 나는 그 의견이 오도/평범한 일 이거나이 코드의 저자가 상당히 선임 C ++ 프로그래머이기 때문에 내가 뭔가 빠졌습니까?

2) OTOH, 클래스가 일부 기술을 사용하여 다형성 (적어도 하나의 가상 함수가 있음)인지 테스트 할 수 있는지 궁금합니다.

3) 클래스가 다형성인지 언제 알고 싶습니까? 거친 추측; 사용하여 클래스의 시작 주소를 얻으려면 dynamic_cast<void*>(T) (처럼 dynamic_cast 다형성 클래스에서만 작동합니다).

당신의 의견을 기다리고 있습니다.

미리 감사드립니다.

도움이 되었습니까?

해결책

해당 유형이 다형성인지 확인하는 데 사용될 수있는 방법을 상상할 수 없습니다. TypeID가 모든 유형에서 작동하기 때문에 그것이 주장하는 데 사용될 수 없습니다. Boost에는 구현이 있습니다 여기. 그것이 필요한 이유에 관해서는 - 내가 아는 한 가지 사례는 Boost.serialization 라이브러리입니다. 비 폴리 흉선 유형을 저장하는 경우 저장할 수 있습니다. 다형성을 저장하는 경우 TypeID를 사용하여 동적 유형을 가져 와서 해당 유형의 직렬화 방법을 호출해야합니다 (일부 테이블에서 찾음).

업데이트: 내가 실제로 틀린 것 같습니다. 이 변형을 고려하십시오.

template <class T> 
bool isPolymorphic() { 
    bool answer=false;
    T *t = new T();
    typeid(answer=true,*t); 
    delete t;
    return answer; 
}

이것은 원래 코드 스 니펫에서 댓글 당 정확하게 이름이 제안한대로 작동합니다. TypeID 내부의 표현은 "다형성 클래스 유형의 LValue를 지정하지 않는 경우"(STD 3.2/2) 평가되지 않습니다. 따라서 위의 경우, t가 다형성이 아닌 경우, TypeID 발현은 평가되지 않습니다. t가 다형성이라면 *t는 실제로 다형성 유형의 lvalue이므로 전체 발현을 평가해야합니다.

이제 원래 예제는 여전히 틀 렸습니다 :-). 사용되었습니다 T(), 아니다 *t. 그리고 T() 만들다 rvalue (STD 3.10/6). 따라서 여전히 "다형성 클래스의 lvalue"가 아닌 표현을 산출합니다.

그것은 상당히 흥미로운 속임수입니다. 반면에 실용적인 가치는 다소 제한적입니다. Boost :: IS_Polymorphic은 컴파일 타임 상수를 제공하기 때문에 런타임 가치를 제공하므로 다형성 및 비 폴리 염색 유형에 대한 다른 코드를 인스턴스화 할 수 없습니다. .

다른 팁



class PolyBase {
public:   
    virtual ~PolyBase(){}
};

class NPolyBase {
public:
    ~NPolyBase(){}
};

template<class T>
struct IsPolymorphic
{
    struct Derived : T {
        virtual ~Derived();
    };
    enum  { value = sizeof(Derived)==sizeof(T) };
};


void ff()
{
    std::cout << IsPolymorphic<PolyBase >::value << std::endl;
    std::cout << IsPolymorphic<NPolyBase>::value << std::endl;
}

C ++ 11 이후로 이것은 이제 <type_traits> 헤더로 std::is_polymorphic. 다음과 같이 사용할 수 있습니다.

struct PolyBase {
  virtual ~PolyBase() {}
};

struct NPolyBase { 
  ~NPolyBase() {}
};

if (std::is_polymorphic<PolyBase>::value)
  std::cout << "PolyBase = Polymorphic\n";
if (std::is_polymorphic<NPolyBase>::value)
  std::cout << "NPolyBase = Also Polymorphic\n";

이것은 "폴리베이스 = 다형성"만 인쇄합니다.

하나는 다음과 같은 사실을 사용할 수 있습니다.

  1. dynamic_cast 인수가 다형성 클래스가 아닌 경우 컴파일 시간에 실패합니다. sfinae와 함께 사용할 수 있습니다.
  2. dynamic_cast<void*> 주소를 반환하는 유효한 캐스트입니다. 완벽한 다형성 대상.

따라서 C ++ 11에서 :

#include <iostream>
#include <type_traits>

template<class T>
auto is_polymorphic2_test(T* p) -> decltype(dynamic_cast<void*>(p), std::true_type{});

template<class T>
auto is_polymorphic2_test(...) -> std::false_type;

template<class T>
using is_polymorphic2 = decltype(is_polymorphic2_test<T>(static_cast<T*>(0)));

struct A {};
struct B { virtual ~B(); };

int main() {
    std::cout << is_polymorphic2<A>::value << '\n'; // Outputs 0.
    std::cout << is_polymorphic2<B>::value << '\n'; // Outputs 1.
}

나는 여기서 약간 혼란스러워서, 내가 놓친 것을 설명하는이 답변에 대한 의견을 얻기를 바라고 있습니다.

확실히 수업이 다형성인지 여부를 알고 싶다면, 당신이해야 할 일은 그것이 지원되는지 묻는 것뿐입니다. dynamic_cast, 맞지 않습니까?

template<class T, class> struct is_polymorphic_impl   : false_type {};
template<class T> struct is_polymorphic_impl
    <T, decltype(dynamic_cast<void*>(declval<T*>()))> : true_type {};

template<class T> struct is_polymorphic :
    is_polymorphic_impl<remove_cv_t<T>, void*> {};

누구 든지이 구현에서 결함을 지적 할 수 있습니까? 나는 하나가 있어야한다고 생각합니다. 부스트 문서 계속 주장하고 있습니다 is_polymorphic "C ++ 언어로는 포용 적으로 구현할 수 없습니다".

그러나 "휴대 할 수 없을 정도로"는 일종의 족제비입니다. 아마도 그들은 MSVC가 Expression-Sfinae를 지원하지 않는 방법을 암시하거나 내장 C ++와 같은 일부 방언이 지원하지 않습니다. dynamic_cast. 어쩌면 그들이 "C ++ 언어"라고 말할 때 그들은 "C ++ 언어의 가장 낮은 공통-노미 네이터 하위 집합"을 의미합니다. 그러나 나는 그들이 말하는 것을 의미한다는 잔소리의 의심이 있습니다. 나는 뭔가 빠진 사람.

그만큼 typeid OP의 접근 방식 (rvalue가 아닌 LValue를 사용하기 위해 나중에 답변으로 수정)도 괜찮은 것처럼 보이지만 ConstexPR은 아니며 실제로는 A를 구성해야합니다. T, 매우 비쌀 수 있습니다. 그래서 이거 dynamic_cast 접근 방식은 어떤 이유로 작동하지 않는 한 더 좋아 보인다. 생각?

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