C ++의 템플릿 유형에서 char* 이름을 얻을 수 있습니까?
문제
템플릿 유형의 문자열 이름 (const char*)을 얻고 싶습니다. 불행히도 나는 RTTI에 액세스 할 수 없습니다.
template< typename T >
struct SomeClass
{
const char* GetClassName() const { return /* magic goes here */; }
}
그래서
SomeClass<int> sc;
sc.GetClassName(); // returns "int"
이게 가능해? 나는 길을 찾을 수없고 포기하려고합니다. 도와 주셔서 감사합니다.
해결책
아니요, 그리고 그것은 typeid와 신뢰할 수 없습니다. 컴파일러 구현에 의존하는 내부 문자열을 제공합니다. "int"와 같은 것은 "I"도 일반적입니다. int
.
그건 그렇고, 당신이 원하는 것이 두 유형이 동일한 지 비교하는 경우 먼저 문자열로 변환 할 필요가 없습니다. 당신은 그냥 할 수 있습니다
template<typename A, typename B>
struct is_same { enum { value = false }; };
template<typename A>
struct is_same<A, A> { enum { value = true }; };
그리고 그렇게합니다
if(is_same<T, U>::value) { ... }
부스트는 이미 그러한 템플릿이 있으며 다음 C ++ 표준에는 std::is_same
도.
유형의 수동 등록
다음과 같은 유형을 전문화 할 수 있습니다.
template<typename>
struct to_string {
// optionally, add other information, like the size
// of the string.
static char const* value() { return "unknown"; }
};
#define DEF_TYPE(X) \
template<> struct to_string<X> { \
static char const* value() { return #X; } \
}
DEF_TYPE(int); DEF_TYPE(bool); DEF_TYPE(char); ...
따라서 사용할 수 있습니다
char const *s = to_string<T>::value();
물론 유형을 알려지지 않은 경우 컴파일 시간 오류를 받으려면 기본 템플릿 정의를 제거 할 수도 있습니다 (전방 선언 만 유지). 나는 단지 완료를 위해 여기에 포함시켰다.
나는 이전에 Char Const*의 정적 데이터 멤버를 사용했지만, 그것들을 선언 할 곳 등의 질문과 같은 복잡한 문제를 일으킨다. 위와 같은 클래스 전문화는 문제를 쉽게 해결합니다.
GCC에 따라 자동
또 다른 방법은 컴파일러 내부에 의존하는 것입니다. GCC에서 다음은 합리적인 결과를 제공합니다.
template<typename T>
std::string print_T() {
return __PRETTY_FUNCTION__;
}
반환 std::string
.
std::string print_T() [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]
약간 substr
마법이 혼합되어 있습니다 find
당신이 찾는 문자열 표현을 줄 것입니다.
다른 팁
정말 쉬운 솔루션 : someclass의 생성자에게 문자열 객체를 전달하는 것입니다.
예시:
#define TO_STRING(type) #type
SomeClass<int> s(TO_STRING(int));
간단히 저장하고 getClassName의 구현에 표시하십시오.
약간 더 복잡한 솔루션이지만 여전히 매우 쉽습니다.
#define DEC_SOMECLASS(T, name) SomeClass<T> name; name.sType = #T;
template< typename T >
struct SomeClass
{
const char* GetClassName() const { return sType.c_str(); }
std::string sType;
};
int main(int argc, char **argv)
{
DEC_SOMECLASS(int, s);
const char *p = s.GetClassName();
return 0;
}
템플릿 비 유형 솔루션 :
또한 자신의 유형 ID를 만들고 ID 및 문자열 표현으로 전환 할 함수를 가질 수 있습니다.
그런 다음 유형을 템플릿이 아닌 매개 변수로 선언 할 때 ID를 전달할 수 있습니다.
template< typename T, int TYPEID>
struct SomeClass
{
const char* GetClassName() const { return GetTypeIDString(TYPEID); }
};
...
SomeClass<std::string, STRING_ID> s1;
SomeClass<int, INT_ID> s2;
당신은 이와 같은 것을 시도 할 수 있습니다 (이것은 내 머리 꼭대기에서 떨어져 있기 때문에 컴파일 오류 등이있을 수 있습니다.)
template <typename T>
const char* GetTypeName()
{
STATIC_ASSERT(0); // Not implemented for this type
}
#define STR(x) #x
#define GETTYPENAME(x) str(x) template <> const char* GetTypeName<x>() { return STR(x); }
// Add more as needed
GETTYPENAME(int)
GETTYPENAME(char)
GETTYPENAME(someclass)
template< typename T >
struct SomeClass
{
const char* GetClassName() const { return GetTypeName<T>; }
}
이것은 당신이 추가하는 모든 유형에 대해 작동합니다. GETTYPENAME(type)
라인. 관심있는 유형을 수정하지 않고 작동하며 내장 및 포인터 유형에서 작동한다는 이점이 있습니다. 사용하려는 모든 유형에 대한 선이 있어야한다는 별개의 단점이 있습니다.
내장 된 RTTI를 사용하지 않으면 Brian R. Bondy의 답변이나 Dirkgently 's Will이 작동하는 정보를 직접 추가해야합니다. 내 대답과 함께 해당 정보를 추가 할 세 가지 위치가 있습니다.
- 객체 생성 시간을 사용하여
SomeClass<int>("int")
- Dirkgently의 Compile-Time RTTI 또는 가상 함수를 사용하는 클래스에서
- 내 솔루션을 사용하여 템플릿을 사용합니다.
세 가지 모두 효과가있을 것입니다. 상황에서 가장 적은 유지 보수 두통으로 끝날 수있는 문제 일뿐입니다.
RTTI에 액세스 할 수 없으므로 typeid (t) .name ()를 사용할 수 없습니까? 그것이 컴파일러의 도움으로 그것을하는 유일한 방법이기 때문입니다.
유형이 고유 한 이름을 갖는 것이 매우 중요합니까, 아니면 이름이 어떻게 든 지속될 것입니까? 그렇다면 코드에 선언 된 클래스 이름보다 더 강력한 것을 제공하는 것을 고려해야합니다. 다른 네임 스페이스에 넣어 두 개의 클래스에 동일한 자격이없는 이름을 줄 수 있습니다. Windows의 두 개의 다른 DLL에 동일한 이름 (네임 스페이스 자격 포함)을 가진 두 개의 클래스를 넣을 수도 있으므로 이름에도 DLL을 식별해야합니다.
그것은 모두 당신이 끈으로 무엇을할지에 달려 있습니다.
약간의 마법을 직접 추가 할 수 있습니다. 같은 것 :
#include <iostream>
#define str(x) #x
#define xstr(x) str(x)
#define make_pre(C) concat(C, <)
#define make_post(t) concat(t, >)
#define make_type(C, T) make_pre(C) ## make_post(T)
#define CTTI_REFLECTION(T, x) static std::string my_typeid() \
{ return xstr(make_type(T, x)); }
// the dark magic of Compile Time Type Information (TM)
#define CTTI_REFLECTION(x) static const char * my_typeid() \
{ return xstr(make_type(T, x)); }
#define CREATE_TEMPLATE(class_name, type) template<> \
struct class_name <type>{ \
CTTI_REFLECTION(class_name, type) \
};
// dummy, we'll specialize from this later
template<typename T> struct test_reflection;
// create an actual class
CREATE_TEMPLATE(test_reflection, int)
struct test_reflection {
CTTI_REFLECTION(test_reflection)
};
int main(int argc, char* argv[])
{
std::cout << test_reflection<int>::my_typeid();
}
나는 검사관을 만들 것이다 static
기능 (따라서 비const
).
아니, 죄송합니다.
int에서 사용하려고하면 RTTI가 컴파일되지 않습니다.