문제
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 ++에 대해 이야기하고 있습니다.
해결책
다른 사람이 언급했듯이 C ++ 0X는 이것을 언어로 내장하고 있습니다. 그때까지는 추천합니다 Bjarne Stroustrup'에스 템플릿 제약 조건에 대한 제안.
edit2 : C ++ 0x에서 개념이 제거되었습니다.
다른 팁
C ++ 11을 사용하는 경우 사용할 수 있습니다. static_assert
~와 함께 std::is_base_of
이 목적을 위해.
예를 들어,
#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");
// ...
}
}
"암시 적으로"는 정답입니다. 템플릿은 컴파일하는 방식으로 인해 "오리 타이핑"시나리오를 효과적으로 만듭니다. 템플릿 유형 값에서 원하는 함수를 호출 할 수 있으며, 허용되는 유일한 인스턴스화는 해당 메소드가 정의 된 것입니다. 예를 들어:
template <class T>
int compute_length(T *value)
{
return value->length();
}
우리는이 메소드를 선언하는 모든 유형에 대한 포인터에서 호출 할 수 있습니다. length()
반환 방법 int
. 따라서 :
string s = "test";
vector<int> vec;
int i = 0;
compute_length(&s);
compute_length(&vec);
...하지만 유형에 대한 포인터는 아닙니다. ~ 아니다 선언하다 length()
:
compute_length(&i);
이 세 번째 예제는 컴파일되지 않습니다.
C ++는 각 인스턴스화에 대해 새 버전의 템플릿 기능 (또는 클래스)을 컴파일하기 때문에 작동합니다. 그 컴파일을 수행함에 따라, 유형-점검 전에 템플릿 인스턴스화의 직접적이고 거의 거시적 인 대체를 코드로 대체합니다. 모든 것이 여전히 해당 템플릿으로 작동하면 컴파일이 진행되고 결국 결과에 도달합니다. 실패한 경우 (같은 int*
선언하지 않습니다 length()
), 우리는 두려운 6 페이지 템플릿 컴파일 타임 오류를 얻습니다.
아무것도하지 않는 ifoo에 가드 유형을 넣을 수 있습니다. foo의 t에 있는지 확인하십시오.
class IFoo
{
public:
typedef int IsDerivedFromIFoo;
};
template <typename T>
class Foo<T>
{
typedef typename T::IsDerivedFromIFoo IFooGuard;
}
체크 아웃 후원
부스트 컨셉 체크 라이브러리 (BCCL)
개념 확인 라이브러리를 사용하면 명시 적 진술과 확인을 추가 할 수 있습니다. 개념 스타일로 제안 된 C ++ 언어 확장.
일종의. ifoo *에 static_cast가있는 경우 발신자가 ifoo *에 할당 할 수있는 클래스를 통과하지 않는 한 템플릿을 인스턴스화하는 것은 불가능합니다.
암시 적으로 만.
실제로 호출되는 메소드에서 사용하는 모든 메소드는 템플릿 매개 변수에 부과됩니다.
할 수 있어요. 기본 템플릿을 만듭니다. 개인 생성자 만 갖습니다. 그런 다음 허용하려는 각 케이스에 대한 전문화를 만듭니다 (또는 허용되지 않은 목록이 허용 목록보다 훨씬 작은 경우 반대).
컴파일러를 사용하면 개인 생성자와 함께 버전을 사용하는 템플릿을 인스턴스화 할 수 없습니다.
이 예제는 int 및 float와의 인스턴스화 만 허용합니다.
template<class t> class FOO { private: FOO(){}};
template<> class FOO<int>{public: FOO(){}};
template<> class FOO<float>{public: FOO(){}};
짧고 우아한 방법은 아니지만 가능합니다.
CRTP 패턴을보십시오 (호기심으로 재귀 템플릿 패턴). 정적 인물을 지원하도록 설계되었습니다.