• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

템플릿 상속을 받지 않고 부분적 특수화할때 오류

20.12.17 01:47 작성 조회수 387

3

안녕하세요. 강의 정말 잘 듣고 있습니다.

템플릿을 부분적으로 특수화할때 상속을 받아서 void print()함수를 char타입에 대해 특수화를 해주셨잖아요.

그런데 앞 강의에서 member function을 특수화할때처럼 전체 부모 클래스를 상속받지 않고 그냥 print()함수만 char타입에 대해 특수화하면 안되나 해서 해봤는데 오류가 나더라구요.

즉, 강의에서 보여주셨던 부분을 주석처리하고 제가 member function부분만 특수화를 해봤는데..  template argument list must match the parameter list 라는 오류가 나더라구요. 앞 강의에서는 아래와 같은 member function 특수화할때 별 문제가 없었는데 무슨 차이인건가요?

//template <int size>

//class StaticArray<char, size> : public StaticArray_BASE<char, size>

//{

//public:

// void print()

// {

// for (int count = 0; count < size; ++count)

// std::cout << (*this)[count];

// std::cout << endl;

// }

//};

template<int size>

void StaticArray<char, size>::print()

{

for (int count = 0; count < size; ++count)

std::cout << *(this)[count];

std::cout << std::endl;

}

답변 2

·

답변을 작성해보세요.

12

안소님의 프로필

안소

2020.12.17

"부분 특수화"란 템플릿 매개변수가 여러개일 경우 매개 변수들 중 일부만 특수화하는 것을 뜻합니다. 

질문자님께서 언급하신 "앞 강의"가 <13.4 : 함수 템플릿 특수화> 강의에서 멤버 함수를 특수화 했던 것에 대해 말씀하시는게 맞나요?

<13.4 : 함수 템플릿 특수화> 강의에서의 멤버 함수 특수화가 클래스 바깥에서 이루어지는게 가능했던 이유는 위와 같이 클래스 템플릿의 모든 매개변수를 전부 특수화했기 때문입니다.(매개변수가 T 한 개밖에 없는 상황에서 T를 double로 특수화 했기 때문에 모든 매개변수를 특수화했다고 볼 수 있습니다) 즉, 이 경우는 질문자님께서 질문 주신 강의의 주제였던 "부분 특수화"가 아닌 "완전 특수화"입니다. 클래스 템플릿의 모~~든 매개 변수를 전부 다 특수화 하여 "완전 특수화"를 할 때만 이렇게  멤버 함수를 클래스 바깥에서 특수화시키는게 가능합니다. 그래서 <13.4> 강의에선 클래스 바깥에서 특수화해도 문제가 없었던 것입니다.

이번 강의에서 다룬 예제 코드 또한 마찬가지로 멤버 함수 print() 를 클래스 바깥에서 특수화 하려면 이렇게 2 개의 템플릿 매개변수인 T 와 size 이렇게 2 개의 변수들을 전부 다 특수화 해주어야만 이렇게 바깥에서 특수화가 가능해지게 됩니다. 이렇게 매개변수들 2 개 다 전부 특수화해준 경우에는 딱히 문제가 없는 것을 확인할 수 있습니다. T는 char로, size는 3으로 구체화되는 경우에는 특별히 "This is <char, 3> Type" 문장을 출력하도록 특수화 했는데 별 오류 없이 잘 출력된 것을 확인할 수 있습니다. 이렇게 템플릿의 매개 변수들을 전부 다 완전 특수화하는 경우에는 이렇게 질문자님이 하고싶으셨던 것 처럼 클래스 바깥에서 문제 없이 특수화가 가능하다는 것을 확인할 수 있습니다.

그러나 이렇게 2 개의 매개 변수 중 T 하나만 "부분적으로 특수화"시키려는 경우에는  template argument list must match the parameter list 오류메세지가 뜨는 것을 확인할 수 있습니다. T는 char로 특수화 시켰는데 size는 특수화하지 않아 여전히 size죠. 멤버 함수를 클래스 외부에서 특수화 할 땐 "부분 특수화"는 허용되지 않습니다. 오직 "완전 특수화"할 때만 클래스 외부에서 특수화가 가능합니다. 그 이유는 부분 특수화가 함수의 오버로딩을 복잡하게 해서인 것 같다고 하네요. 그 이유에 대해서는 참고 링크 참조해주세요. 클릭1, 클릭2 

질문자님이 에러가 나신 결론적인 이유는 클래스 바깥에서 T만 부분적으로 특수화 하려고 했기 때문입니다. 아무튼 템플릿 매개변수들이 여러개일 때 그 중 일부만 부분적으로 특수화 하려고 하는 경우에는 멤버 함수를 클래스 바깥에서 특수화하기는 어렵다.라고만 이해해주시면 될 것 같습니다. 

그럼 멤버 함수를 부분 특수화 하고 싶을 땐 어떻게 할까요? 첫번째로 특수화하지 않고 멤버 함수 자체를 다른 버전으로 오버로딩 되도록 추가하는 방법이 있겠습니다. 근데 예제 코드의 print() 멤버함수 같은 경우엔 매개변수가 필요 없기 때문에 이 방법은 좀 어렵겠습니다. 두번째 해결 방법으로는 클래스 자체를 부분 특수화 해서 그 클래스 안에서 멤버 함수를 정의하는 것입니다. 즉, 이렇게 멤버 함수를 부분특수화 시키려면 반드시 클래스 안에서만 이루어져야 해요! 

클래스 자체는 부분 특수화가 가능하기 때문에 T만 char로 부분 특수화한 클래스 내에서 이렇게 멤버 함수 print() 를 특수화할 수 있습니다. 이 멤버 함수 print()는 StaticArray_BASE<char, size> 클래스에 속한 함수이기 때문에 size는 제외하고 T만 char 로 부분특수화가 되었어요. 근데 이 코드의 문제점은 클래스가 <char, size> 타입으로 객체를 만들었을 경우엔 전체 멤버가 오직 저 print() 가 끝이라는게 된다는 것입니다. 즉, <char, size> 타입으로 구체화 되었을땐 getArray 멤버함수도 없고.. m_array 멤버도 없고.. [] 연산자 오버로딩도 없는 셈입니다. 그냥  <char, size> 타입으로 구체화 될땐 StaticArray_BASE 클래스 멤버가 print() 꼴랑 이게 끝인게 됩니다. 그래서 교수님께서 "상속"을 사용하신 것입니다.

StaticArray_BASE 로 부터 모든 멤버들을 물려 받은 StaticArray 클래스의 <char, size> 부분 특수화는, 클래스 내부에 print() 언급하고 있더라도 getArray도, m_array도 가지고 있습니다. StaticArray_BASE로부터 물려받았기 때문이에요. 따라서  <char, size> 타입으로 인스턴스화 되었을 때도 문제 없이 getArray, m_array 이런것들 다 사용할 수 있게 됩니다.

2

홍길동님의 프로필

홍길동

2021.01.08

어제 하루동안 스트레스 이빠이 받아서 컴퓨터 꺼버렸는데 오늘 답변보고 다시 다음 챕터로 넘어갑니다.

감사합니다!!