2012-10-03 2 views
3

나는 Mesh 클래스를 위해 일반적으로 프로그래밍하려고했다. 뿐만 아니라,여기에 템플릿을 잘못 사용한 적이 있습니까?

Mesh<T>는 3D 모양의 정점을 포함 (나는 경우에 당신은 질문을 생각하고,이 은 GPU에서 수행 할이 아닌 이유입니다, 메쉬를 변형 CPU 변환이 필요합니다) (꼭지점이 합쳐져서 삼각형을 만들 때) 얼굴을 맞춘다.

여기서 T은 꼭지점의 유형이며, 일부 유형의 모델에는 PNCT 유형 (위치, 표준, 색상, 텍 스코드)이 있고 다른 것은 PC (위치, 색상)입니다.

물론
struct VertexPNCT { 
    Vector3 pos, normal ; 
    Vector4 color ; 
    Vector2 tex ; 
} ; 

struct VertexPC { 
    Vector3 pos ; 
    Vector4 color ; 
} ; 

, 모든 정점 위치를 가지고!

하지만 여기 내 문제가 있습니다.

Mesh<T>transform 메서드를 구현해야합니다. 그 방법은 잘 작동, (.pos를) 물론, 모든 정점 포맷이 위치를 가지고 있으며,이 지속적으로 이름 않다면 :

난 항상 Vertex* 구조체에 해당 멤버 .pos를 호출하는 경우 모든 정점 확실히, 위치를 가질 것이기 때문에,

void transform(Matrix4& mat) 
{ 
    each vertex 
     vertex.pos = mat * vertex.pos ; // transform it 
} 

지금 여기 나사이야 : 그때로 템플릿 클래스 Mesh<T>에 방법 .transform를 추가 할 수 있습니다. 정점 형식에 일반 형식이있는 경우 해당 법선을 "일반 매트릭스"로 변형해야합니다. 이제 템플릿에 "if 문"이 생깁니 까? 각각의 버텍스 유형 (기본적으로 2 개의 카테고리, 법선이있는 클래스 및 법선이없는 클래스)으로 템플릿 전문화 .transform 메소드를 작성해야합니까?

여기 템플릿을 잘못 사용한 적이 있습니까? "프로그래밍 보트"를 놓친 건가요? 여기

정말 논리적으로 수행 할 작업은 다음과 같습니다

void transform(Matrix4& mat) 
{ 
    each vertex in vertices 
    { 
     vertex.pos = mat * vertex.pos ; // transform it 
     #ifdef vertex.normal 
     vertex.normal = mat * vertex.normal ; // transform normal as well* 
     #endif 
    } 
} 

* 변환 (당신이 "정상적인 매트릭스"를 사용할 필요가 없습니다)에는 규모 아마

+0

'Matrix4'의 유형은 무엇입니까? 어떤 클래스가'transform' 함수를 보유하고 있습니까 (아니면 자유 함수입니까?) 'vertex'의 타입은 무엇입니까? 모든 질문과 그 이상의 내용이 솔루션에 영향을 미칩니다. 실제 문제에 대해 더 많이 보여줘야합니다. –

+0

나는 그를 올바르게 이해한다면 변형은'메쉬 '클래스에 있다고 생각한다. – CrazyCasta

+0

런타임에 올바른 방법을 선택해야합니다. 또는 정적으로 바인딩 할 수 있습니까? 당신은 아마 정적으로 할 수 있습니다, 당신은 정상적인 매트릭스에 대한 추가 매개 변수를 추가해야합니까? – imreal

답변

1

당신을지지 않습니다 structs 클래스를 만들고 두 개의 기본 클래스 (일반 클래스와없는 클래스)에서 파생 클래스를 파생 시키려합니다. 그런 다음 템플릿 전문화를 사용하여 모든 두 가지 기본 클래스 (모든 정점 클래스 대신)를 선택할 수 있습니다. 당신은 그럼 그냥 비 템플릿 오버로드를 추가 할 수 있습니다, 기본이 바로 위치 (및 .pos 회원)을 보유하고 어디 Vertex의 계층 구조를 작성할 수있는 경우

3

하는 VertexWNormal.normal 보유하고 나머지는 거기에서 상속 컴파일러 핸들 :

void transform(Matrix4& m, VertexBase& v) { 
    // transform only pos 
} 
void transform(Matrix4& m, VertexWNormal& v) { 
    transform(m,static_cast<VertexBase&>(v)); 
    // transform normal here 
} 
void tranform(Matrix4& m) { 
    foreach vertex: 
     transform(m,vertex); 
} 

물론 이것이 디자인과 관련이 있는지 여부는 표시하지 않는 많은 것들에 달려 있습니다.

2

두 가지 유형의 꼭지점이있는 경우 데이비드에서 설명한대로 수행하는 것이 좋습니다. 두 가지 함수를 만들어 변환을 수행하고 꼭지점 유형에 기반한 오버로드를 사용하여 호출하게하십시오.이것은 더 많은 정점 유형에도 적용될 수 있지만 새로운 정점 유형을 추가 할 때마다 함수에 다시 과부하가 필요합니다. 이것은 여기에 설명 된 것과 같이 간단한 함수에 대해서는 괜찮을 수 있지만 함수가 실제로 더 복잡하면 성가 시게 될 수 있습니다.

부분 수정은 특정 정점 유형에 일반 멤버가 있는지 여부를 알려주는 특성 클래스를 만드는 것입니다. 기본값은 그것이 대다수의 경우에서 정확하고 특성에 기초한 적합한 기능이 선택 될 수 있도록 설정 될 수있다. 당신은 여전히 ​​코드의 두 가지 버전을 제공 할 수 있지만, 모든 추가 정점 유형에 필요한 것이 무엇 모두가 특성을 정의하는 것입니다 :

template <typename> struct VertexHasNormal { enum { value = false }; }; 
template <> struct VertexHasNormal<VertexPNCT> { enum { value = true }; }; 

template <typename V, template T, template S> 
void transform(V& vertices, Matrix4& m, T S::*member) { 
    for (auto& v: vertices) { 
     v.*member = mat * v.*member; 
    } 
} 

template <bool, typename T> 
struct Transform { 
    template <typename V> 
    void call(V& vertices, Matrix4& m) { 
     transform(vertices, m, &T::pos); 
    } 
}; 
template <typename T> 
struct Transform<bool, T> { 
    template <typename V> 
    void call(V& vertices, Matrix4& m) { 
     transform(vertices, m, &T::pos); 
     transform(vertices, m, &T::normal); 
    } 
}; 

template <typename T> 
void Mash<T>::transform(Matrix4& m) { 
    Transform<VertexHasNormal::value>::call(this->vertices, m); 
} 

함수 템플릿 transform()은 정점의 순서에 실제 변환을 수행하는 기능입니다. 나는 그것을 고려해 볼 수있는 귀엽다고 생각하기 때문에 그것을 분해했다. 그러나 그것은 고려 될 필요가 없다. 또한, 멤버에 대한 포인터, auto 등을 사용할 필요가 없습니다. Transform 타입은 함수 템플릿이 부분적으로 특수화 될 수 없기 때문에 사용되는 보조 타입입니다. 정점 유형에 normal 구성원의 특성이 있는지 여부에 따라 다릅니다. 마지막으로 Mash<T>::transform()은 특수 기능의 해당 버전으로 전달됩니다.

normal 멤버가있는 다른 버텍스가 정의되면 새로운 특성 전문화를 추가하는 것만 필요합니다. 그것은 바람직하지 않을 수 있습니다. 이 경우 유형 특성을 사용하여 normal이라는 액세스 가능한 데이터 멤버가 구조에 있는지 확인하는 것이 가능합니다. 그러나 나는 내 머리 꼭대기에서 이것을 입력 할 수 있다고 생각하지 않는다. 이를 구현하기위한 기본적인 아이디어는 대체 실패가 오류 (" SFINAE")가 아니며 테스트 된 유형에 필요한 구성원이있는 경우 잠재적 인 두 구성원간에 모호성을 만들도록 설정 될 수 있다는 이점을 활용하는 것입니다. 거기에 Boost 구성 요소가 있지만 그것을 직접 작성해야하는 경우 약 10 줄의 코드입니다.

관련 문제