is_enum에서 __is_enum을 특수화하는 방법이 궁금합니다.

dltkddyd의 이미지

is_enum은 is_enum의 타입인수가 enum으로 명시된 타입이면 integral_constant, 즉 true_type을 상속받고, 그 타입인수가 enum으로 명시된 타입 아니면, integral_constant, 즉 false_type을 상속받습니다. 그리고 이 is_enum의 원형이 헤더에 다음과 같이 정의돼 있습니다.

template<typename _Tp>
struct is_enum: public integral_constant<bool, __is_enum(_Tp)>{ };

그렇다면 __is_enum(_Tp)라는 것이 true 또는 false라는 값으로 대체된다고 추론할 수 있습니다. 그리고 __is_enum이라는 것도 구조체일겁니다. 그렇다면 다음과 같은 식으로 정의돼 있겠죠.

template<typename _Tp>
struct __is_enum:public false_type {};

또는

template<typename _Tp>
struct __is_enum:public true_type {};

헤더 찾아봐도 __is_enum에 대한 정의를 찾아볼 수가 없어서 경험상 저럴것이라고 추측해봤습니다.
그런데 후자의 경우로 __is_enum이라는 일반 구조체 템플릿이 정의돼있다면, false_type을 상속받는 _Tp를 모두 열거해주어야 하는 번거로움이 따릅니다. int라는 타입은 enum이 아니기 때문에 다음과 같이 부분특수화돼어야 합니다.

template<>
struct __is_enum<int>:public false_type {};

double, float, char, unsinged int, unsigned char, wchar_t, char16, char32 등과 같은 다른 기본타입에 대해서도 일일히 이런 식으로 열거해주어야 합니다. 그리고 치명적인 것은 사용자정의 타입의 경우에도 저렇게 해주지 않으면 true_type을 상속받게 된다는 것입니다. 그래서 전자의 방식이 가능하다면 enum으로 선언된 타입만을 명확하게 구분할 수 있는 방식은 전자의 방식이라 생각하게 됐습니다. 그런데 문제는 enum 이라는 것은 타입이 아니기 때문에 enum으로 명시된 타입의 매개변수를 받을 수 없다는 것입니다. 그러니까 true_type을 상속받는 경우를 특수화할 경우에는

template<typename _Tp>
struct __is_enum<enum _Tp>:public false_type {};

저런식으로 is_const에서처럼 const라는 키워드를 따로 떼어내듯한 특수화방식이 허용되지 않는다는 것이죠. 저런식으로 될 수가 없다면 오히려 이 방식은 더 번거로운 방식이 될 것이고, 사용자들은 자신이 만든 enum으로 명시된 모든 타입에 대해 라이브러리를 수정해가면서 __is_enum의 특수화 목록을 다음과 같은 식으로 추가해야 할 겁니다. 가령 Rep라는 enum을 제대로 구분하기 위해

template<>
struct __is_enum<Rep>::public false_type {};
</codE>
 
이런 식으로 구분을 헤더에 추가해야 합니다.  is_const에서 const라는 것을 떼어내듯이 떼어내는 방법은 없을까요?  
mirheekl의 이미지

일례로 http://msdn.microsoft.com/en-us/library/vstudio/ms177194.aspx 여길 보시면 그냥 컴파일러에서 지원하는 기능으로 되어있을 수도 있는 것이죠.

또는 그것을 사용하지 않고 말씀하신 대로 그냥 나열해서 구현한 경우도 있는것 같네요. http://stackoverflow.com/questions/11316912/is-enum-implementation 이걸 보시면..

--

dltkddyd의 이미지

컴파일러에서 지원하는 기능 역시 어딘가에 정의돼있지 않은가요? 그것을 저런 소스 형태로 볼 수는 없는지 궁금합니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

klara의 이미지

말그대로 컴파일러가 컴파일하면서 enum인지 아닌지 소스보고 알아서 처리한다는 뜻입니다. 스펙에 명시된건 is_enum 클래스의 동작이지 구현이 아니니까요.

dltkddyd의 이미지

#include <type_traits>
#include <iostream>
using namespace std;
 
template<typename _Tp>
struct __is_my_enum:public integral_constant<bool,true>{};
template<>
struct __is_my_enum<int>:public integral_constant<bool,false> {};
template<>
struct __is_my_enum<unsigned int>:public integral_constant<bool,false> {};
template<>
struct __is_my_enum<float>:public integral_constant<bool,false>{};
template<>
struct __is_my_enum<double>:public integral_constant<bool,false>{};
template<>
struct __is_my_enum<char>:public integral_constant<bool,false>{};
template<>
struct __is_my_enum<unsigned char>:public integral_constant<bool,false>{};
template<>
struct __is_my_enum<wchar_t>:public integral_constant<bool,false>{};
template<>
struct __is_my_enum<char16_t>:public integral_constant<bool,false>{};
template<>
struct __is_my_enum<char32_t>:public integral_constant<bool,false>{};
 
template<typename _Tp>
struct is_my_enum:public integral_constant<bool, __is_my_enum<_Tp>::value > {};
 
class  AnyClass {};
int main() {
	//여기서는 정상적으로 Enum이라는 문구를 출력
	if(is_my_enum<char>::value) {
		cout<<"Enum."<<endl;
	}
	else {
		cout<<"No enum."<<endl;
	}
 
	//여기서도 Enum이라는 문구를 출력.
	/*꼭 위에
template<>
struct __is_my_enum<AnyClass>:public integral_constant<bool,false>{};
	이런 식으로 언급해야 AnyClass에 대해 No enum이라는 문구를 출력.
*/
	if(is_my_enum<AnyClass>::value) {
		cout<<"Enmu."<<endl;
	}
	else {
		cout<<"No enum."<<endl;
	}
	/*
	이런식으로 하면 사용자는 자신들이 만든 타입(클래스로)에 대해 모두 위와 같이 특수화 방식으로 정의를 해두어야 한다.
	*/
	return 0;
}

저처럼 하면 모든 클래스를 다 언급해야만 클래스를 enum이 아닌 것으로 인식할겁니다. 그런데 type_traits의 is_enum::value의 값은 false입니다. 도대체 뭘로 구현을 한 건지요? 소스에서 C++로는 저 클래스를 구분하는 것이 불가능할 것 같습니다. 뭘 알아야 되는 거죠? 어셈블리라도 배워야 하는건가요?

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

klara의 이미지

std::is_class 를 쓰면되죠. mirheekl님께서 링크해주신거 보긴 하셨어요?
그리고 컴파일러가 알아서 한다는건 말그대로 알아서 한다는 겁니다.
컴파일러는 모든 변수의 타입을 이미 알고 있습니다.
실제 구현이 어떤진 모르겠지만, 컴파일러는 이미 모든 변수의 타입을 알고 있기 때문에 실제 구현을 가지지 않고 확장 키워드로 그런걸 넣는건 얼마든지 가능합니다.

dltkddyd의 이미지

__is_enum 이라는 것에 대한 설명은 어디에도 없네요. 제가 알고 싶은 것은 true 또는 false라는 값을 반환하는 __is_enum 이라는 것입니다. 글에서는 눈을 씻고 찾아봐도 컴파일이 알아서 처리할 뿐 구현은 알 수가 없다는 것이죠? 전 그 구현이 어떻게 돼있는지, 그걸 알고 싶은 겁니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

klara의 이미지

링크를 읽어보시고 쓴 댓글이라면 그렇게 장황하게 구현코드를 적고 각 클래스별로 또 특수화해야되냐는 질문은 안나왔을겁니다.
링크된 글에 이미 is_class를 이용한 구현이 나와있으니까요.

자꾸 '구현'이라고 하시는데 컴파일러가 알아서 하는것에는 지금 말하는 레벨의 구현은 존재하지 않습니다.
__enum_is에 대한 구현을 묻는 건 sizeof 의 구현이 어떻게 되있냐는 질문과 같은 레벨입니다.
그냥 컴파일러가 알아서 구문을 해석해서 원하는 값을 넣어줍니다.
만약 '컴파일'을 어떻게 하냐고 물으시는 거라면 gcc의 소스코드가 공개되있으니 찾아보세요.

dltkddyd의 이미지

그 구현 역시 없습니다. 아마도 여기서 언급된 버전을 말씀하시는 것 같은데요.

template <class _Tp> struct _LIBCPP_VISIBLE is_enum
    : public integral_constant<bool, !is_void<_Tp>::value             &&
                                     !is_integral<_Tp>::value         &&
                                     !is_floating_point<_Tp>::value   &&
                                     !is_array<_Tp>::value            &&
                                     !is_pointer<_Tp>::value          &&
                                     !is_reference<_Tp>::value        &&
                                     !is_member_pointer<_Tp>::value   &&
                                     !is_union<_Tp>::value            &&
                                     !is_class<_Tp>::value            &&
                                     !is_function<_Tp>::value         > {};

네, 여기에 보면 is_class가 있긴 한데, 이건 구현이 아니라 어딘가에 구현돼 있는 것을 사용한 것으로 보입니다. 그리고 저런 식으로 정수가 아니고, 부동소수점도 아니고, 배열도 아니고... 등등의 식으로 해서 그 값을 집어넣는 경우에는 또 이런 질문을 할 수가 있습니다. 그럼 is_class는 어떻게 구현을 하고, is_union은 어떻게 구현을 한 것이죠? 공용체나 클래서 키워드 union, class 역시 타입이 아니라 enum처럼 형을 선언하는 키워드이기 때문이죠. 그러면 그것 역시 구조체가 아니고 공용체가 아니고 ... 등등 하는 식으로 해서 true나 false를 언급한다고 할 겁니다. 그러면 또.. 같은 식의 질문을 할 수 밖에 없을 겁니다. 저런 식이라면. is_class의 구현이 있다고 하셨는데, 어디에 있죠?

그리고 이건 제가 보았던 __DEFINE_SPEC 라는 매크로에 의한 템플릿 생성법을 보고 모방해보건데. 이것도 모든 enum 타입을 언급해주어야 한다는 단점이 있습니다.

enum CapColor {Red, Yellow, Blue, Black, White};
template<typename STARG> struct is_re_my_enum:public integral_constant<bool,false> {};
#define MAKE_TEMP(X) template<> struct is_re_my_enum<X>:public integral_constant<bool,true> {}
MAKE_TEMP(CapColor);//이런 식으로.  간단하게 언급해주기 위해서 매크로를 사용했다.  별 의미는 없음.
 
int main() {
	cout<<is_re_my_enum<CapColor>::value<<endl;
}

멍청한 질문일 수도 있을거고, 그런 것 신경쓰지 않아도 될 것이라고 생각할 수 있겠지만, 그래도 한 번 여쭤보자면, 이런 것이죠. enum은 타입을 만드는 키워드이지 타입 자체는 아니다. enum이라는 것으로 각 프로그래머는 자신만의 타입을 만들어 사용한다. 이러한 모든 열거형만을 인수로 받을 수 있는 키워드라는 것이 존재할까요?

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

klara의 이미지

없으니까 컴파일러가 확장을 하든지 링크된거처럼 줄줄이 아닌거 달았죠.

dltkddyd의 이미지

sizeof 사용하듯이 __is_enum을 사용하라는 말씀으로 알고 쓰면 간단한데. 머리속은 계속 넘넘 생각으로 갈피를 못 잡는듯합니다. 사실 저 sizeof에 대해 생각해본 적 없이 그냥 사용하긴 했는데, 그렇게 말씀하시니, 이번에는 도대체 저 sizeof가 뭔지 더 궁금해지는 것은 왠지?

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

klara의 이미지

sizeof도 지금 생각하시는 레벨의 구현은 존재하지 않습니다. 그런 키워드들은 컴파일러가 구문을 해석하면서 알아서 처리합니다.
그 '알아서'라는 과정이 소스코드로부터 목적코드를 생성하는 과정, 즉 컴파일 그 자체입니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.