기본 기능이없는 C ++ 템플릿 전문화
-
06-07-2019 - |
문제
잘 컴파일하고 잘 작동하는 다음 코드가 있습니다.
template<typename T>
T GetGlobal(const char *name);
template<>
int GetGlobal<int>(const char *name);
template<>
double GetGlobal<double>(const char *name);
그러나 "기본"기능을 제거하고 싶습니다. 즉, GetGlobal에 모든 전화를 걸고 싶습니다.u003Ct> 여기서 't'는 int가 아니거나 두 배의 오류가 아닙니다.
예를 들어, getGlobalu003Cchar> ()는 컴파일 타임 오류 여야합니다.
기본 기능을 삭제하려고했지만 상상했듯이 많은 오류가 발생했습니다. 그렇다면 기능의 특수 버전에만 호출을 허용하는 방법이 있습니까?
감사!
해결책
컴파일 타임 오류를 얻으려면 다음과 같이 구현하십시오.
template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined
부스트를 사용하면 더 우아하게 만들 수 있습니다.
template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
C ++ 표준은 0과 같은 크기를 가진 유형이 없으므로 컴파일 타임 오류가 발생합니다.
처럼 SBI 그의 의견에서 마지막으로 마지막으로 줄일 수 있습니다.
template<typename T>
T GetGlobal(const char *name) { char X[!sizeof(T)]; }
첫 번째 솔루션은 다른 솔루션을 선호합니다. 왜냐하면 다른 솔루션은 다른 솔루션보다 더 명확한 오류 메시지 (적어도 시각적 C ++에서)를 제공하기 때문입니다.
다른 팁
오래되고 구식 질문이지만 주목할 가치가있을 수 있습니다. C++11
삭제 된 기능을 사용 하여이 문제를 해결했습니다.
template<typename T>
T GetGlobal(const char *name) = delete;
template<>
int GetGlobal<int>(const char *name);
업데이트
아래에서 컴파일되지 않습니다 MacOS llvm 8
. 여전히 4 살짜리 결함이 매달려 있기 때문입니다 (참조 이 버그 보고서).
다음 해결 방법은 문제에 맞습니다 (사용 static_assert
건설하다).
template<typename T>
T GetGlobal(const char *name) {
static_assert(sizeof(T) == 0, "Only specializations of GetGlobal can be used");
}
template<>
int GetGlobal<int>(const char *name);
업데이트
Visual Studio 15.9는 동일한 버그를 가지고 있습니다. 이전 해결 방법을 사용하십시오.
구현하지 않으면 최소한 링커 오류가 발생합니다. 컴파일 타임 오류를 원한다면 클래스 템플릿으로이를 수행 할 수 있습니다.
template<typename T>
struct GlobalGetter;
template<>
struct GlobalGetter<int> {
static int GetGlobal(const char *name);
};
template<>
struct GlobalGetter<double> {
static double GetGlobal(const char *name);
};
template<typename T>
T GetGlobal(const char *name)
{
return GlobalGetter<T>::GetGlobal(name);
}
나는 실제로 구현을 제공하지 말고, 그 방법의 맨손 선언만을 제안합니다.
다른 옵션은 컴파일 타임 어제를 사용하는 것입니다. 부스트에는 많은 짐승이 있습니다.
namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
boost::same_type<T, int> >));
메시지 버전도 있습니다.
다음은 부스트를 사용하는 대체 기술입니다.
typedef를 종속 이름으로 선언하십시오
이것은 'T'가 교체되었을 때만 발생하지 않기 때문에 작동합니다. 이것은 유사한 (그러나 합법적 인) 버전의 예제입니다. 키릴
template <typename T>
T GetGlobal (const char * name) {
typedef typename T::DONT CALL_THIS_FUNCTION;
}
불완전한 반환 유형을 사용하십시오
이 기술은 전문화에 효과가 없지만 과부하에는 효과가 있습니다. 아이디어는 불완전한 유형을 반환하는 함수를 선언하는 것이 합법적이지만 호출하지 않는다는 것입니다.
template <typename T>
class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name);