C ++ 전문화, type_of 또는 Just TypeId
-
20-09-2019 - |
문제
내 상황에서 사용하는 것이 무엇인지, 그 이유를 알고 싶습니다. 우선 RTTI (typeid)를 사용하는 것이 나쁘다고 들었습니다. 누구든지 이유를 설명 할 수 있습니까? 정확히 유형을 알고 있다면 런타임에서 비교하는 것이 무엇입니까? 또한 boost :: type_of를 사용하는 방법이 있습니까? 나는 Mighty Google을 통해 검색하는 것을 발견하지 못했습니다 :) 나를위한 다른 솔루션은 전문화이지만, 적어도 9 가지 유형의 새로운 방법을 전문화 할 것입니다. 다음은 필요한 예입니다.
이 수업이 있습니다
template<typename A, typename B, typename C>
class CFoo
{
void foo()
{
// Some chunk of code depends on old A type
}
}
그래서 나는 TypeID를 확인하고 (내가 들었던 것은 나쁘다) 다음과 같은 예 에서이 3 가지 실현을해야합니다.
void foo()
{
if (typeid(A) == typeid(CSomeClass)
// Do this chunk of code related to A type
else
if (typeid(B) == typeid(CSomeClass)
// Do this chunk of code related to B type
else
if (typeid(C) == typeid(CSomeClass)
// Do this chunk of code related to C type
}
그렇다면 최상의 솔루션은 무엇입니까? 모든 유형에는 3 개의 전문화가 있기 때문에 모든 A, B, C를 전문화하고 싶지는 않습니다. 따라서 9 가지 방법을 얻 거나이 TypeID 확인을받을 수 있습니다.
해결책
때문에 나쁘다
- A, B 및 C는 컴파일 타임에서 알려져 있지만 런타임 메커니즘을 사용하고 있습니다. TypeId를 호출하면 컴파일러는 메타 데이터를 객체 파일에 포함시켜야합니다.
- "유형과 관련된이 코드 덩어리"를 CSOMECLASS의 인터페이스를 사용하는 실제 코드로 바꾸면 A! = CSOMECLASS 및 호환되지 않는 인터페이스가있는 경우 코드를 컴파일 할 수 없습니다. 컴파일러는 코드가 실행되지 않더라도 여전히 코드를 번역하려고합니다. (아래 예제 참조)
일반적으로하는 것은 코드를 별도의 기능 템플릿 또는 전문화 할 수있는 클래스의 정적 멤버 기능으로 고려하는 것입니다.
나쁜:
template<typename T>
void foo(T x) {
if (typeid(T)==typeid(int*)) {
*x = 23; // instantiation error: an int can't be dereferenced
} else {
cout << "haha\n";
}
}
int main() {
foo(42); // T=int --> instantiation error
}
더 나은:
template<typename T>
void foo(T x) {
cout << "haha\n";
}
void foo(int* x) {
*x = 23;
}
int main() {
foo(42); // fine, invokes foo<int>(int)
}
건배, s
다른 팁
일반적으로 RTTI없이 솔루션을 제시 할 수 있습니다. 그것은 당신이 소프트웨어의 디자인을 올바르게 생각하지 않았다는 것을 보여줄 수 있습니다. 그건 나빠. 때때로 RTTI ~할 수 있다 그래도 좋은 일이 되십시오.
그럼에도 불구하고 당신이하고 싶은 일에는 이상한 것이 없습니다. 다음과 같이 설계된 임시 템플릿을 만들 수 없습니까?
template< class T > class TypeWrapper
{
T t;
public:
void DoSomething()
{
}
};
그런 다음 다음과 같이 원하는 기능을 부분적으로 전문화하십시오.
template<> class TypeWrapper< CSomeClass >
{
CSomeClass c;
public:
void DoSomething()
{
c.DoThatThing();
}
};
그런 다음 수업에서 위의 정의에서 당신은 ...와 같은 일을 할 것입니다.
주형
class CFoo
{
TypeWrapper< A > a;
TypeWrapper< B > b;
TypeWrapper< C > c;
void foo()
{
a.DoSomething();
b.DoSomething();
c.DoSomething();
}
}
이런 식으로 부분적으로 특수한 템플릿을 통과하는 경우 실제로 "dosomething"호출에서 무언가를 수행합니다.
문제는 모든 전문화에 대해 쓰는 코드 덩어리에 있습니다.
글을 쓰면 상관 없습니다 (길이로)
void foo()
{
if (typeid(A) == typeid(CSomeClass)
// Do this chunk of code related to A type
else
if (typeid(B) == typeid(CSomeClass)
// Do this chunk of code related to B type
else
if (typeid(C) == typeid(CSomeClass)
// Do this chunk of code related to C type
}
또는
void foo()
{
A x;
foo_( x );
B y;
foo_( y );
C z;
foo_( z );
}
void foo_( CSomeClass1& ) {}
void foo_( CSomeClass2& ) {}
void foo_( CSomeClass3& ) {}
두 번째 사례의 상승점은 클래스 D를 추가 할 때 컴파일러에 써야 할 FOO_ 누락에 대한 오버로드가 있음을 상기시키는 것입니다. 이것은 첫 번째 변형에서 잊을 수 있습니다.
나는 이것이 처음에 작동하지 않을까 걱정됩니다. 유형이 csomeclass가 아닌 경우에도 "코드 청크"는 컴파일 할 수 있어야합니다.
나는 type_of가 도움이 될 것이라고 생각하지 않습니다 (C ++ 0x의 Auto 및 Decltype와 동일하다면).
이 세 덩어리를 별도의 기능으로 추출하고 Csomeclass에 대해 각각 과부하 할 수 있다고 생각합니다. (편집 : 오, 거기 있습니다 else if's
. 그러면 실제로 많은 과부하/전문화가 필요할 수 있습니다. 이 코드는 무엇입니까?)
edit2 : 코드가 다음과 동등한 일을하기를 희망하는 것으로 보입니다. 여기서 int는 특수 유형입니다.
#include <iostream>
template <class T>
bool one() {return false; }
template <>
bool one<int>() { std::cout << "one\n"; return true; }
template <class T>
bool two() {return false; }
template <>
bool two<int>() { std::cout << "two\n"; return true; }
template <class T>
bool three() {return false; }
template <>
bool three<int>() { std::cout << "three\n"; return true; }
template <class A, class B, class C>
struct X
{
void foo()
{
one<A>() || two<B>() || three<C>();
}
};
int main()
{
X<int, double, int>().foo(); //one
X<double, int, int>().foo(); //two
X<double, double, double>().foo(); //...
X<double, double, int>().foo(); //three
}
어딘가에 추상화가 잘못되었다고 생각합니다.
나는 그들이 노출시키는 데 필요한 인터페이스 측면에서 A, B & C를 재정의하려고 시도합니다 (순수한 가상 방법을 사용한 C ++의 추상 기본 클래스).
템플릿은 기본적으로 오리 유형을 허용하지만 CFOO는 AB & C 클래스에 대해 너무 많이 알고있는 것처럼 들립니다.
typeid는 다음과 같이 나쁘다.
- TypeId는 비싸고 부풀어 오른 바이너리, 필요하지 않은 추가 정보를 제공합니다.
- 모든 컴파일러가 지원하는 것은 아닙니다
- 기본적으로 클래스 계층 구조를 깨고 있습니다.
권장하는 것은 리팩토링입니다. 템플릿을 제거하고 대신 A, B & C의 인터페이스를 정의하고 CFOO가 해당 인터페이스를 가져 오도록하십시오. 이렇게하면 A, B & C가 실제로 응집력있는 유형이되도록 동작을 리팩터링해야합니다.