std::is_same 가 제대로 작동하지 않는것 같습니다.


안녕하세요 c++, stl 코드 작성에 약간의 에러가 발생하여 질문드립니다. 먼저 에러가 나는 코드는 아래와 같습니다. 주석 처리한 곳에서 에러가 납니다.

template<typename T>
void D::Store() {
    // remove all type cvr.
    using originalType = std::decay_t<std::remove_pointer_t<T> >;
    originalType* component = new originalType();

    if(std::is_same<originalType, A>::value) { // 에러!!
        this->mA = component;
    } else if(std::is_same<originalType, B>::value) { // 에러!!
        this->mB = component;
    } else if(std::is_same<originalType, C>::value) { // 에러!!
        this->mC = component;
    }
    mComponents.push_back(component);
}

A,B,C 라는 타입이 미리 정의가 되어있고 그 타입에 해당하는 포인터가 클래스에 멤버로 정의되어 있습니다.

class D {
    D();
    ~D();

    template<typename T>
    void Store();

private:
    A* mA;
    B* mB;
    C* mC;
    std::vector<Parent*> mComponents;
}

사용 용도는 만약 store 로 넘기는 타입 T 가 A,B,C타입중 하나라면 해당하는 멤버의 포인터에 저장후 vector자료형에 캐싱하는 용도입니다. 물론 A,B,C타입은 전부 Parent를 상속받고 있구요. 그 외에도 클래스 타입 E,F ... 등등 Parent를 상속받는 여러 클래스들이 있습니다.

그런데 std::is_same하는 부분에서 에러가 나옵니다. 에러 메세지는 Assigning to 'A*' from incompatible type 'originalType*' (aka 'E*") 이런 에러가 뜹니다.

제가 원하는것은 딱 A,B,C타입이 주어졌을 때만 멤버 변수에 저장하고 싶은 것인데 어떻게 해야 제대로 작동하게 할 수 있을까요?

참고로 개발 환경은 xcode 7.3.1 버전 이구요, os 는 os x el capitan 입니다.

  • 2016년 08월 28일에 작성됨

조회수 104


2 답변


트릭에 가까운 방법인데요. dynamic_cast를 써보시면 어떨까합니다.

void D::Store(Parent *t) {
    if(dynamic_cast<A*>(t)) {
        this->mA = (A*)t;
    } else if (dynamic_cast<B*>(t)) { 
        this->mB = (B*)t;
    } else if (dynamic_cast<C*>(t)) {
        this->mC = (C*)t;
    }
    mComponents.push_back(t);
}

Parent의 소멸자가 virtual로 선언되어야 dynamic_cast가 가능합니다.

  • 2016년 08월 28일에 작성됨
    그렙에서 웹 프론트 개발을 하고 있습니다.

  • 함수 설계상 인자로 받는게 아니라 템플릿 으로 받는 구조라서 이방법은 힘들것 같네요    bodguy   2016.8.29 11:52     

템플릿이 특수화될 때, 컴파일러는 특수화된 버전을 컴파일하려고 시도합니다. 예를 들어서, Store<A>를 특수화할 때를 생각해 봅시다.

template<>
void D::Store<A>() {
    A* component = new A(); // 뭐 정확히 이건 아니지만.. 중요한건 아니니까요.

    if(std::is_same<A, A>::value) {
        this->mA = component;
    } else if(std::is_same<A, B>::value) {
        this->mB = component; // Error
    } else if(std::is_same<A, C>::value) {
        this->mC = component; // Error
    }
    mComponents.push_back(component);
}

설령 if문의 조건부가 false라고는 해도, 어쨋건 코드는 적법한 C++ 코드여야 합니다. this->mB (혹은 mC)와 component의 타입 불일치로 인해 오류가 나죠. Cygwin GCC 5.4.0에서는 이런 에러 메시지를 보여주네요.

test.cpp: In instantiation of ‘void D::Store() [with T = A]’:
test.cpp:53:15:   required from here
test.cpp:35:18: error: cannot convert ‘originalType* {aka A*}’ to ‘B*’ in assignment
         this->mB = component;

이런 문제 때문에 템플릿 메타프로그래밍을 할 때에는 단순히 if를 사용하지 않습니다. 대신 if의 역할을 하는 것이 몇몇 있는데, 이 경우에는 tag dispatch라는 기법이 적합해 보입니다.

struct tag_none { };
struct tag_A { };
struct tag_B { };
struct tag_C { };

template <typename T>
struct component_tag { using type = tag_none; };
template <>
struct component_tag <A> { using type = tag_A; };
template <>
struct component_tag <B> { using type = tag_B; };
template <>
struct component_tag <C> { using type = tag_C; };

class D
{
public:
    template <typename T>
    void Store();

private:
    void Store_impl(void*, tag_none);
    void Store_impl(A* component, tag_A);
    void Store_impl(B* component, tag_B);
    void Store_impl(C* component, tag_C);

    A *mA;
    B *mB;
    C *mC;
    std::vector<Parent*> mComponents;
};

template <typename T>
void D::Store()
{
    using originalType = std::decay_t<std::remove_pointer_t<T> >;
    originalType* component = new originalType();

    Store_impl(component, typename component_tag<originalType>::type { });

    mComponents.push_back(component);
}

void D::Store_impl(void*, tag_none)
{
    // do nothing
}

void D::Store_impl(A* component, tag_A)
{
    mA = component;
}

void D::Store_impl(B* component, tag_B)
{
    mB = component;
}

void D::Store_impl(C* component, tag_C)
{
    mC = component;
}

코드에서 보시다시피, tag라는 여분의 인수를 통해 함수 오버로딩을 하는 것이죠. 여기 실제로 컴파일되는 예제입니다.

  • 2016년 09월 13일에 작성됨

로그인이 필요한 기능입니다.

Hashcode는 개발자들을 위한 무료 QnA사이트 입니다. 작성한 답변에 다른 개발자들이 댓글을 작성하거나 좋아요/싫어요를 할 수 있기 때문에 계정을 필요로 합니다.
► 로그인
► 계정만들기
Close