템플릿 클래스 멤버 함수의 명시 적 전문화


88

특정 유형에 대한 템플릿 멤버 함수를 전문화해야합니다 ( double 이라고 가정 해 보겠습니다 ). 클래스 X자체가 템플릿 클래스가 아닌 동안 잘 작동 하지만 템플릿을 만들면 GCC가 컴파일 타임 오류를 제공하기 시작합니다.

#include <iostream>
#include <cmath>

template <class C> class X
{
public:
   template <class T> void get_as();
};

template <class C>
void X<C>::get_as<double>()
{

}

int main()
{
   X<int> x;
   x.get_as();
}

여기에 오류 메시지가 있습니다

source.cpp:11:27: error: template-id
  'get_as<double>' in declaration of primary template
source.cpp:11:6: error: prototype for
  'void X<C>::get_as()' does not match any in class 'X<C>'
source.cpp:7:35: error: candidate is:
  template<class C> template<class T> void X::get_as()

어떻게 해결할 수 있으며 여기서 문제는 무엇입니까?

미리 감사드립니다.


2
이것은 현재 표준에서 불법입니다. 전문화하려면 수업도 전문화해야합니다 ...
Nim

그러나 클래스가 템플릿이 아닌 경우 작동합니다. 그것도 불법입니까?
ledokol 2011

아니, 완벽하게 괜찮습니다.이 규칙이 적용되는 것은 클래스 템플릿에만 해당됩니다 (AFAIK).
Nim 2011

답변:


108

그런 식으로 작동하지 않습니다. 다음과 같이 말해야하지만 정확 하지 않습니다.

template <class C> template<>
void X<C>::get_as<double>()
{

}

명시 적으로 특수화 된 멤버도 명시 적으로 전문화 하려면 주변 클래스 템플릿이 필요합니다. 따라서 다음과 같이 말해야합니다. 이는 X<int>.

template <> template<>
void X<int>::get_as<double>()
{

}

주변 템플릿을 특수화하지 않으려면 몇 가지 선택 사항이 있습니다. 나는 과부하를 선호한다

template <class C> class X
{
   template<typename T> struct type { };

public:
   template <class T> void get_as() {
     get_as(type<T>());
   }

private:
   template<typename T> void get_as(type<T>) {

   }

   void get_as(type<double>) {

   }
};

type<>래퍼 가 왜 필요한 가요? 타입의 포인터에 대한 0의 캐스트가 T트릭을 할 수 없습니까? 그다지 우아하지 않은 것 같아요 ...
Nim

정말 불가능한 것 같습니다. 감사.
ledokol 2011-04-01

3
@Nim 맞아요, 포인터 캐스트가 추악하다고 생각하며 포인터를 만들 수없는 유형 (참조)에는 작동하지 않습니다. 또한 함수 매개 변수가 크기가없는 배열 유형에 대한 포인터가되는 것은 C ++에서 불법입니다. 유형 래퍼에 포함하면 모든 유형에서 작동합니다.
Johannes Schaub-litb 2011

2
@ JohannesSchaub-litb : 과부하에 따른 다른 선택은 무엇입니까? 그들 중 일부를 보여줄 수 있습니까?
Jean-Bernard Jansen 2014

2
@ 자신의 코멘트가 사용하는 것이었다 빠른 반사 신경 template<typename T> void get_as(T*); void get_as(double*);과를 전달합니다 (T*)0.
Johannes Schaub-litb

24

사용할 수 있다면 std::enable_ifSFINAE에 의존 할 수 있습니다 (대체 실패는 오류가 아닙니다).

그렇게 작동합니다 ( LIVE 참조 ).

#include <iostream>
#include <type_traits>

template <typename C> class X
{
public:
    template <typename T, 
              std::enable_if_t<!std::is_same_v<double,T>, int> = 0> 
    void get_as() { std::cout << "get as T" << std::endl; }

    template <typename T, 
              std::enable_if_t<std::is_same_v<double,T>, int> = 0> 
    void get_as() { std::cout << "get as double" << std::endl; }
};

int main() {
   X<int> d;
   d.get_as<double>();

   return 0;
}

추악한 것은 이러한 모든 enable_if의 유일한 전문화가 컴파일러에 대해 사용 가능해야한다는 것입니다. 그렇지 않으면 명확성 오류가 발생합니다. 그렇기 때문에 기본 동작 "get as T"에도 활성화 if가 필요합니다.


더 현대적으로 만들기 위해 게시물을 업데이트했습니다.
Gabriel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.