2012-10-17 2 views
1

기본 클래스의 멤버 함수를 전문화하고 싶습니다. 그러나 컴파일되지 않습니다. 컴파일하는 대안을 아는 사람이 있습니까? 여기 상속 된 멤버 함수의 템플릿 전문화

이이 Foo<char>()에 전화를 제외하고, 컴파일

struct Base 
{ 
    template<typename T> 
    void Foo() 
    { 
     throw "Foo() is not defined for this type"; 
    } 
}; 

struct Derived : public Base 
{ 
    template<> 
    void Foo<int>() { cout << "Foo<int>()" << endl; } // compile error (cannot specialize members from a base class) 

    template<> 
    void Foo<double>() { cout << "Foo<double>()" << endl; } // compile error (cannot specialize members from a base class) 
}; 
+0

다형성 현상이 없을 것입니다. 템플릿을 가상으로 만들 수는 없습니다. 달성하고자하는 것이 확실하지 않습니다. – CashCow

+0

우리는 특수 멤버가있는 팩토리 클래스를 만들려고 노력하고 있으며 메서드가 특수화되지 않은 유형을 처리하는 방법을 모르는 경우에는 예외를 throw하려고합니다. 예제에서 Derived와 같은 여러 클래스를 만들려고합니다. 그렇지 않으면 우리는 Base 클래스를 가지지 못했을 것입니다. – Alex

+0

런타임에 예외를 throw하는 것보다 컴파일 타임에 실패하는 것이 더 좋습니다. – CashCow

답변

0

예입니다

#include <iostream> 
#include <string> 
using namespace std; 

struct Base 
{ 
    template<typename T> 
    void Foo() 
    { 
     throw "Foo() is not defined for this type"; 
    } 
}; 

struct Derived : public Base 
{ 
    template<typename T> void Foo(); 
}; 

template<> 
void Derived::Foo<int>() { cout << "Foo<int>()" << endl; } 

template<> 
void Derived::Foo<double>() { cout << "Foo<double>()" << endl; } 

int main() 
{ 
    Derived derived; 

    // this is client code 
    derived.Foo<int>(); 
    derived.Foo<double>(); 
    derived.Foo<char>(); // this throws 
} 

당신이 Foo<char>()에 대한 호출을 원하는 경우 - 또는 유형은 특별히으로 전문하지 - 그러면 효과가 있습니다. 당신은 모든 종류의 일이 아닌 전문 구현을 원한다면, 당신은뿐만 아니라 Foo()의 비 전문 구현을 추가해야합니다

template<typename T> 
void Derived::Foo() { cout << "generic" << endl; } 
+0

파생 된 .Foo 가 발생하지 않습니다. 단지 컴파일되지 않습니다 (링크 오류). 또한 더 많은 전문화가 포함 된 DerivedMore를 사용하여 Derived 클래스를 확장 할 수 없습니다. 다른 아이디어가 있습니까? – Alex

+0

@Alex : 단순히 'Derived :: Foo'에 대한 기본 구현을 추가 할 수 있습니다. return Base :: Foo (); – dyp

+0

@DyP : 가능하지만 모든 파생 형식에 추가해야합니다. . 내가 그것들을 많이 가지고 있다면 어떻게 될까? – Alex

1

은 결국, 우리가 오버로드를 사용하여 해결했다. 여기

여기

struct Base 
{ 
    template<typename T> 
    class OfType {} 

    template<typename T> 
    void Foo(OfType<T>) { static_assert(false, "Foo is not implemented for this type. Please look in the compiler error for more details."); } 
}; 

struct Derived : public Base 
{ 
    using Base::Foo; 

    void Foo(OfType<int>) { // here comes logic for ints } 
    void Foo(OfType<double>) { // here comes logic for doubles } 
}; 

이의 대답의 코멘트보기 (알렉스와 토론에 대한 응답으로 Foo()

template<typename S> 
class ClassThatUsesFoo 
{ 
    private: S s; 

    template<typename T> 
    void Bar(T item) 
    { 
     s.Foo(Base::OfType<T>()); // this is the code that uses Foo 
     DoSomeStuffWithItem(item); 
    } 
}; 

void main() 
{ 
    ClassThatUsesFoo<Derived> baz; 
    baz.Bar(12); // this will internally use Foo for ints 
    baz.Bar(12.0); // this will use Foo for doubles 
    baz.Bar("hello world"); // this will give a verbose compile error 
} 
+0

하지만 왜 던지기를 원합니까? 그냥 컴파일하지 않으면 더 좋습니다. – CashCow

+0

정확합니다. 나는 그것을 정적 어설 션으로 변경하거나 완전히 제거 할 것이다. 어쨌든 오버로드를 통해 파생 클래스의 계층 구조를 만들 수 있습니다. 전문성이 내가 할 수없는 것. – Alex

+0

그런데 컴파일러 오류가 링크 오류보다 낫다는 것은 코드에서 잘못된 과부하를 사용하는 위치를 알려주고 단순히 존재하지 않는 것 (아는 것)이 아니라 간단합니다. 다른 점은 main은 int를 void로 반환하지 않으며 예외를 throw하면 std :: exception에서 파생 된 예외를 throw합니다. – CashCow

0

를 사용하는 클라이언트 코드의 예처럼 기본 클래스는 모습입니다 존 디 블링), 이것은 내가 의미 한 바입니다 (SSCCE) :

#include <iostream> 
using namespace std; 

struct Base 
{ 
    template<typename T> 
    void Foo() 
    { 
     //static_assert(false, "Foo() is not defined for this type"); 
     throw "Foo() is not defined for this type"; 
    } 
}; 
    // you can add as many specializations in Base as you like 
    template <> 
    void Base::Foo<char>() { cout << "Base::Foo<char>()" << endl; } 


struct Derived : public Base 
{ 
    // just provide a default implementation of Derived::Foo 
    // that redirects the call to the hidden Base::Foo 
    template < typename T > 
    void Foo() 
    { Base::Foo<T>(); } 
}; 
    // the specializations for Derived 
    template<> 
    void Derived::Foo<int>() { cout << "Foo<int>()" << endl; } 

    template<> 
    void Derived::Foo<double>() { cout << "Foo<double>()" << endl; } 


struct Derived_wo_specialization : public Base 
{ 
    /* nothing */ 
}; 


int main() 
{ 
    Derived d; 
    d.Foo<char>(); 
    d.Foo<double>(); 

    Derived_wo_specialization dws; 
    dws.Foo<char>(); 
    dws.Foo<double>(); 
} 
관련 문제