2008-09-23 3 views
49

C#에서 우리는 제네릭 매개 변수로 사용할 수있는 형식에 제약 조건을 부과하는 제네릭 형식을 정의 할 수 있습니다.템플릿 제약 C++

interface IFoo 
{ 
} 


class Foo<T> where T : IFoo 
{ 
} 

class Bar : IFoo 
{ 
} 

class Simpson 
{ 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Foo<Bar> a = new Foo<Bar>(); 
     Foo<Simpson> b = new Foo<Simpson>(); // error CS0309 
    } 
} 

우리는 C에서 템플릿 매개 변수에 대한 제약 조건을 부과 할 수있는 방법 ++ 있습니까 : 다음 예는 일반적인 제약의 사용 방법을 보여줍니다.


C++ 0x는 기본 지원이 있지만 현재 표준 C++에 대해 이야기하고 있습니다.

+0

네마냐 말했듯이, 부스트는 비슷한 구현하는 라이브러리가있다. 적절한 언어 기능을 갖춘 경우보다 약간 자세한 정보가 표시되지만 작동하며 대부분의 제약 조건을 표현할 수 있습니다. – jalf

답변

31

다른 사람이 언급했듯이 C++ 0x가이 언어를 기본 언어로 사용하고 있습니다. 그때까지 Bjarne Stroustrup 님의 suggestions for template constraints을 권하고 싶습니다.

편집 : Boostalternative of its own입니다.

편집 2 : concepts have been removed from C++0x처럼 보입니다.

+2

이 ... 그리고 아마도에 다시 추가 [C++는 1Y (http://stackoverflow.com/questions/15669592/what-are-the-differences-between-concepts-and-template-constraints)를 – Yakk

1

묵시적으로 만.
실제로 호출되는 메서드에서 사용하는 모든 메서드가 template 매개 변수에 적용됩니다.

8

체크 아웃 Boost

개념 확인 라이브러리가 하나가 명시 적으로 문과 proposed C++ language extension의 스타일 concepts의 확인을 추가 할 수 있습니다 라이브러리 (BCCL)를 점검하여 부스트 개념입니다.

2

일종의. IFoo *에 static_cast를하면 호출자가 IFoo *에 할당 할 수있는 클래스를 전달하지 않으면 템플릿을 인스턴스화 할 수 없습니다.

31

"암시 적으로"정답입니다. 템플리트는 컴파일되는 방식으로 효과적으로 "오리 입력"시나리오를 작성합니다. 템플리트 유형 값에서 원하는 모든 함수를 호출 할 수 있으며 허용되는 유일한 인스턴스 화는 해당 메소드가 정의 된 것입니다. 예를 들어 :

template <class T> 
int compute_length(T *value) 
{ 
    return value->length(); 
} 

우리는 int를 반환하는 length() 방법을 선언 모든 유형에 대한 포인터에이 메서드를 호출 할 수 있습니다. thusly 히 :

string s = "test"; 
vector<int> vec; 
int i = 0; 

compute_length(&s); 
compute_length(&vec); 

은 ...하지만하지 않는 유형에 대한 포인터에 하지length()를 선언 :

compute_length(&i); 

이 세 번째 예는 컴파일되지 않습니다.

이 기능은 C++이 각 인스턴스화에 대해 templatized 함수 (또는 클래스)의 새 버전을 컴파일하기 때문에 가능합니다. 컴파일을 수행함에 따라 형식 확인 전에 코드에 템플릿 인스턴스화를 직접 매크로 방식으로 대체합니다. 그 템플릿으로 모든 것이 여전히 작동하면 컴파일이 진행되고 결국 결과에 도달하게됩니다. 아무 것도 실패하면 (예 : int*이 (가) length()으로 선언되지 않은 경우), 두려운 6 페이지 템플릿 컴파일 타임 오류가 발생합니다.

class IFoo 
{ 
public: 
    typedef int IsDerivedFromIFoo; 
}; 

template <typename T> 
class Foo<T> 
{ 
    typedef typename T::IsDerivedFromIFoo IFooGuard; 
} 
+1

난 당신을 생각 코멘트에 쓰는 것으로 충분하다고 말하는가? '// T 그렇지 않으면 컴파일 후 우리는 우리 모두가 거룩한 "개념"개념을 기다리고 있습니다이 때문에 지칠대로 지친 여섯 페이지 템플릿 컴파일 시간 error' (LOL)를 얻을' – bobobobo

+0

을 fail' 것, BaseA에서 상속해야합니다. – TechNyquist

14

당신은 확실히 그것을 푸에 T에있을 수 있도록, 아무것도하지 않는 IFoo에 가드 유형을 넣을 수 있습니다. 기본 템플릿을 만듭니다. Private 생성자 만 만듭니다. 그런 다음 허용하려는 각 사례에 대한 전문화를 작성하십시오 (또는 허용되지 않는 목록이 허용 된 목록보다 훨씬 작 으면 반대로 설정하십시오).

컴파일러는 개인 생성자가있는 버전을 사용하는 템플릿을 인스턴스화하는 것을 허용하지 않습니다.

이 예제는 int 및 float로 인스턴스화 만 허용합니다.

template<class t> class FOO { private: FOO(){}}; 

template<> class FOO<int>{public: FOO(){}}; 

template<> class FOO<float>{public: FOO(){}}; 

짧고 우아한 방법이 아니라 가능합니다.

0

당신은 그것을 할 수 있습니다 :

-1

CRTP 패턴 (Curiously Recursive Template Pattern)을 살펴보십시오. 정적 상속을 지원하도록 설계되었습니다.

+0

CRTP 실제로 특정 아무것도 설계되지 않았습니다 ... 나는 그것이 _discovered_ 디자인보다는 ([생각 "이 관용구의 이름은 최초의 C++ 템플릿 코드의 일부를 관찰했다 짐 코플리 엔에 의해 만들어졌다." ] (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)) 템플릿 매개 변수에 제약 조건을 두는 것은 분명히 매우 유용합니다. – leftaroundabout

30

당신은 C++ (11),이 목적을 위해 std::is_base_ofstatic_assert을 사용할 수 있습니다 사용하는 경우. 예를 들어

,

#include <type_traits> 

template<typename T> 
class YourClass { 

    YourClass() { 
     // Compile-time check 
     static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass"); 

     // ... 
    } 
} 
+2

완벽! * 더 많은 캐릭터가 필요합니다 ... * –