[질문] 괴롭습니다. -_- template 관련 에러...

bizzare의 이미지

GCC 3.2x 에서 잘 컴파일되던 소스가
새로 페도라64비트 버전을 깔고서
거기에 있는 3.4버전으로 컴파일을 하니
어마어마하게 많은 에러가 나는군요. -_-;;;;;

대표적인 에러가 다음과 같은 에러입니다. :shock:

---------------------------------------------------------------------
there are no arguments to `clear' that depend on a template parameter, so a declaration of `clear' must be available
---------------------------------------------------------------------

소스를 보면 다음과 같은 식으로 stl::list를 상속받아 만든 템플릿 클래스를 만들어서 사용한 부분에서 난 에러입니다. (주요부분만 뽑아온 코드입니다.)

template < class _Ty ,class _A = std::allocator < _Ty > >
class MyList : public std::list< _Ty , _A > {
public:
void MyClear()
{
clear();
}
}

윈도우에서도 컴파일이 잘 되고 이전버전의 GCC에서도 잘 되던 것인데.. 왜 GCC 3.4버전에선 안되는 것인지.. -_-;;;

도와주세요..

doldori의 이미지

에러 나는 것이 정상입니다. 다음처럼 고치세요.

template < class _Ty ,class _A = std::allocator < _Ty > > 
class MyList : public std::list< _Ty , _A > { 
public: 
    void MyClear() 
    { 
        std::list<_Ty, _A>::clear(); 
    } 
};

관련 문법은 argument dependent lookup(Koenig lookup)과 point of instantiation에
나와 있는데 복잡해서 저도 정확히는 모릅니다. 혹시 잘 알고 계신 분은 설명 좀 해주세요.
ixevexi의 이미지

doldori wrote:
에러 나는 것이 정상입니다. 다음처럼 고치세요.
template < class _Ty ,class _A = std::allocator < _Ty > > 
class MyList : public std::list< _Ty , _A > { 
public: 
    void MyClear() 
    { 
        std::list<_Ty, _A>::clear(); 
    } 
};

관련 문법은 argument dependent lookup(Koenig lookup)과 point of instantiation에
나와 있는데 복잡해서 저도 정확히는 모릅니다. 혹시 잘 알고 계신 분은 설명 좀 해주세요.

호곡.. doldori님이 모르는 것 등장!! :wink:

C++, 그리고 C++....
죽어도 C++

kane의 이미지

구글신께서 계시를 내려주셨습니다.
http://gcc.activeventure.org/Name-lookup.html

template 의존 문맥의 (변수/함수) 이름과 template 독립 문맥의 (변수/함수) 이름을 구분한다고 합니다.

template < class _Ty ,class _A = std::allocator < _Ty > > 
class MyList : public std::list< _Ty , _A > { 
public: 
void MyClear() 
  { 
    clear(); 
  } 
}

여기서 clear()는 template 독립 문맥입니다. (확인하지는 않았지만) std::list<>의 clear()는 template 의존 문맥일 것입니다. 서로 문맥이 달라서 clear()를 찾지 못하고 있는 것입니다.
clear() 대신 this->clear()나 std::list<_Ty,_A>::clear() 를 사용해서 문제를 해결할 수 있다고 합니다.

gcc 3.4에서 문제가 발생한 이유는 two-stage name lookup (위에서 설명한 내용)이 3.4에서부터 구현되었기 때문입니다. (라고 위 링크에 써 있습니다. :) )

== 여기서 부터는 질문입니다. ==

위 링크의 예제

void foo(double);
     
struct A {
  template <typename T>
  void f () {
    foo (1);        // 1
    int i = N;      // 2
    T t;
    t.bar();        // 3
    foo (t);        // 4
  }
     
  static const int N;
};

를 보면, 1번과 4번이 문맥이 다릅니다. (1번은 template independent, 4번은 template dependent)
문맥이 다르다는 것까지는 이해를 할 수 있겠습니다만, 너무 복잡하다는 느낌이 듭니다. 이렇게까지 구분해야하는 이유가 있을까요?
(TC++PL 읽으러 가야겠습니다. ㅠㅠ)
kane의 이미지

ixevexi wrote:
doldori wrote:
에러 나는 것이 정상입니다. 다음처럼 고치세요.
template < class _Ty ,class _A = std::allocator < _Ty > > 
class MyList : public std::list< _Ty , _A > { 
public: 
    void MyClear() 
    { 
        std::list<_Ty, _A>::clear(); 
    } 
};

관련 문법은 argument dependent lookup(Koenig lookup)과 point of instantiation에
나와 있는데 복잡해서 저도 정확히는 모릅니다. 혹시 잘 알고 계신 분은 설명 좀 해주세요.

호곡.. doldori님이 모르는 것 등장!! :wink:


그러게요. 흔치 않은 일입니다. :)
htna의 이미지

제가보기에는
1. 컴파일러의 속도향상
2. 모호한 구문제거 (물론 전체 코드상 모호하지는 않습니다만...)
을 위한 고려가 아닌가 생각이 드네요..

// included by "TBase.h"
template<typename T>
class TBase {
    void clear() { cout << "TBase::clear()" << endl; }
};

// included by "clear.h"
void clear() { cout << "::clear()" << endl; }

// included by "TDerived.h"
template<typename T> class TBase;
template<typename T>
class TDerived : public TBase<T> {
    void callClear() {
        clear();
    }
}

여기에서 TDerived<T>::callClear() 를 해석하기 위해서 선결되는 문제들을 해결해야만 합니다. 즉 TBase<T> 에 clear()가 있는지 없는지, 자신의 base class들에 clear()가 있는지를 없는지를 확인해야만 할 것입니다. 다른말로는 컴파일 해 보기 전에 어떻게 프로그램이 돌아갈 지 예측할 수 없다는 것입니다.(cpp화일로 합쳐져서 compile되기 이전에는)
만약에 자신의 base들 중에 clear()가 없다면, 이때에는 global의 clear()를 호출해야 할 것이기 때문입니다.

또한, 이러한 모호성이 해결된다면, 컴파일러 쪽에서 중간컴파일된 템플릿정보를 그냥 (그때그때 다시컴파일 하지 않고) 이용하면 될 것이기에, 컴파일러의 성능향상에 득이 있지 않나 생각합니다...
여담이지만, template object file같은게 나오지 않을까 생각이 드네요... 만약 그렇게 된다면 template class를 포함하고 있는 소스를 컴파일 할 때 드는 시간이 획기적으로 줄어들을수도, 참고로 template가 코드상에 복잡하게 추가되면 전체적인 컴파일 속도가 현저하게 느려지는점이 있죠...

그래서 저렇게 하지 않았을까 합니다.
더구나, 다들 알다시피 C++의 표준을 완전히 지키는 컴파일러는 없다고 들었습니다. 그만큼 문법/내용/구현이 복잡하다는 얘기이겠죠... 그러한 미구현된 내용중 하나를 해결한게 아닌가 생각이 듭니다.
어쩌면 VC7.0의 아성을 누르기 위해(??) C++표준을 좀 더 적극적으로 따라간게 아닌가 하는 생각도 든다는..
VC개발자의 헛소리였습니다.
^^;;;

PS:
그리고,

void foo(double); 
      
struct A { 
  template <typename T> 
  void f () { 
    foo (1);        // 1 
    int i = N;      // 2 
    T t; 
    t.bar();        // 3 
    foo (t);        // 4 
  } 
      
  static const int N; 
};

문제는 대략 맞다고 생각이 듭니다.
T가 string일 겨우에는 foo(double)를 호출해 줄 수 없고, foo(string)이 있을 경우에, foo(string)을 호출해 줘야 할 것입니다.
같은 맥락으로 본다면, T가 int일경우에는 foo(double)를 호출해 주는게 맞는지는 생각해 볼 문제입니다. 만약 foo(int)가 있다면요..
하지만 foo(1)의 입장에서는, struct A가 정의/선언된 시점에서 명확하게 foo(double)을 호출 해 줄 수 있으므로, foo(double)을 호출해 주는게 맞다고 생각이 되네요...

틀린부분이 있거든 지적해 주시기 바랍니다.

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

익명 사용자의 이미지

http://gcc.gnu.org/gcc-3.4/changes.html

In a template definition, unqualified names will no longer find members of a dependent base (as specified by [temp.dep]/3 in the C++ standard).

여기도 설명이 나와 있습니다.

에러메시지 구글검색해보고, this->clear();로 고쳐보시라고 답변을 쓰고 어제 9시 정각 쯤에 제출을 클릭했는데 네트워크가 그때 다운돼서 안올라갔네요 OTL

익명 사용자의 이미지

팔자에도 없는 appendix까지 보게 되었군요. 평생 볼 일이 없을 줄 알았습니다. ㅠㅜ Stroustrup C.13.8 Name Binding에 관련 내용이 나와있네요. 아직 이해가 안되는 부분도 있지만, 위에 제가 쓴 글이 오해의 소지도 있고 해서 정리해보겠습니다.

이름은 template 의존적인 이름과 독립적인 이름이 있습니다.
template 의존적인 이름은 instantiation 할 때 이름 찾기를 하고, 독립적인 이름은 definition 할 때 이름 찾기를 한다고 합니다. 다시 말하면 의존적인 이름은 사용할 때, 독립적인 이름은 정의할 때 이름 찾기를 합니다.

template < class _Ty ,class _A = std::allocator < _Ty > > 
class MyList : public std::list< _Ty , _A > { 
public: 
    void MyClear() 
    { 
        clear(); 
    } 
}; 

위의 경우, clear()는 독립적인 이름이므로 definition 할 때 이름 찾기를 합니다. 하지만 그 시점에서 부모 클래스(std::list<_Ty,_A>)가 결정되지 않았으므로 부모 클래스의 멤버 함수 이름을 사용할 수 없습니다. 따라서 자식 클래스(MyList)의 멤버 함수에서 clear()를 찾아보고 없으면, 다시 글로벌 clear()를 찾습니다.
this->clear()나 std::list<_Ty,_A>::clear()로 의존적인 이름을 만들면 initiation 할 때 이름을 찾습니다. 그 때는 이미 부모 클래스가 결정되어 있으므로 부모 클래스의 멤버 함수 이름을 사용할 수 있게 됩니다.
(언제 이름 찾기를 하느냐에 따라 이름을 찾고, 못찾는 경우가 발생하는거지 서로 다른 문맥끼리만 이름을 공유하는 것은 아닙니다.)
kane의 이미지

언제 로그아웃이 됐죠? :shock:
이름찾기에 대해서 쓴 손님은 접니다.

htna wrote:
또한, 이러한 모호성이 해결된다면, 컴파일러 쪽에서 중간컴파일된 템플릿정보를 그냥 (그때그때 다시컴파일 하지 않고) 이용하면 될 것이기에, 컴파일러의 성능향상에 득이 있지 않나 생각합니다...
여담이지만, template object file같은게 나오지 않을까 생각이 드네요... 만약 그렇게 된다면 template class를 포함하고 있는 소스를 컴파일 할 때 드는 시간이 획기적으로 줄어들을수도,

컴파일러 쪽은 모르지만, name lookup을 바꿨다고 컴파일 하는데 큰 이득이 있을지는 의문이네요. 부모 클래스를 뒤지는 수고는 덜겠지만 컴파일 정보의 재사용 여부에 영향을 미칠 문제는 아닐 것 같습니다. (컴파일러 책을 보러 가야하나? -_-;; )
저도 template object 같은게 있으면 좋겠다고 생각한 적이 있습니다만, 제작자들이 "export"를 구현하기 전까지는 어렵지 않을까요.
htna wrote:
참고로 template가 코드상에 복잡하게 추가되면 전체적인 컴파일 속도가 현저하게 느려지는점이 있죠...

Stroustrup을 읽다보니 C.13.10 Explicit Instantiation에 다음과 같은 구절이 있네요.
Quote:
The link-time and recompilation efficiency impact of instantiation requests can be significant. I have seen examples in which bundling most template instantiations into a single compilation unit cut the compile time from a number of hours to the equivalent number of minutes.

자세한 내용은 없어서 어떤 식으로 했는지는 불분명하지만 explicit instantiation을 이용한 것 같습니다. 이 쪽으로 찾아보시면 컴파일 시간을 줄이는데 도움이 되지 않을까 싶습니다.
doldori의 이미지

네, kane님 설명이 맞는 것 같습니다. 그런데 제가 아직도 알지 못하는 것은...

void foo(int);

template<typename T>
struct S
{
    void f()
    {
        foo(1);  // (1)
        T t;
        foo(t);  // (2)
    }
};

void foo(int*);

// <--- point of instantiation
int main()
{
    S<int*> a;
    a.f();
}

(1)에서 foo는 dependent name이 아니므로 point of definition binding이 적용되고
void foo(int)를 호출할 것입니다. 그리고 (2)에서는 dependent name이므로 point of
instantiation binding이 적용될 것이고요. 그리고 point of instantiation에서
void foo(int*)가 scope에 있으므로 이 코드는 컴파일이 되어야 할 거라고 생각했습니다.
gcc나 VC++에서는 컴파일이 되는데 최후의 보루인 Comeau에서 거부하는군요.
어느 쪽이 맞는지 모르겠습니다. -_-a
kane의 이미지

"int*"의 namespace는 어딘가요?

void foo(int); 

template<typename T> 
struct S 
{ 
    void f() 
    { 
        foo(1);  // (1) 
        T t; 
        foo(t);  // (2) 
    } 
}; 

class C {}; // modified
void foo(C); // modified

// <--- point of instantiation 
int main() 
{ 
    S<C> a; // modified
    a.f(); 
}

http://www.comeaucomputing.com/tryitout/ 에서 테스트 했을 때 위 코드는 문제없이 컴파일됐습니다. 제가 잘못 생각하고 있는게 아니라면 instantiation binding이 제대로 동작하고 있는 것 같습니다. 이제 왜 "int*"일 때는 안됐는가가 문제인데..

http://library.n0i.net/programming/c/cp-iso/template.html 에서 14.6.4 - Dependent name resolution [temp.dep.res]는 다음과 같습니다.

Quote:
-1- In resolving dependent names, names from the following sources are considered:

* Declarations that are visible at the point of definition of the template.
* Declarations from namespaces associated with the types of the function arguments both from the instantiation context (temp.point) and from the definition context.


정의한 순간에 visible하거나 type of argument와 같은 namespace에 있는 이름을 찾는다는 의미인 것 같습니다. (사실 visible의 명확한 의미는 모르겠습니다만.. 대략 그 이전에 선언되었다는 의미로 이해하고 있습니다.)
그렇다면 class C와 foo(C)는 같은 namespace로 처리가 됐는데, int*와 foo(int*)는 같은 namespace로 처리되지 않는게 아닌가 하는 추측이 가능합니다. 그래서 맨 처음 int*의 namespace에 대해서 물어본 건데..
물론 이건 어디까지나 제 추측에 불과합니다. 저도 왜 S<int*> a; 는 에러가 발생하는지 모르겠습니다. comeau가 잘못된 건 아닐까요? :wink:
doldori의 이미지

kane wrote:
"int*"의 namespace는 어딘가요?
void foo(int); 

template<typename T> 
struct S 
{ 
    void f() 
    { 
        foo(1);  // (1) 
        T t; 
        foo(t);  // (2) 
    } 
}; 

class C {}; // modified
void foo(C); // modified

// <--- point of instantiation 
int main() 
{ 
    S<C> a; // modified
    a.f(); 
}

http://www.comeaucomputing.com/tryitout/ 에서 테스트 했을 때 위 코드는 문제없이 컴파일됐습니다. 제가 잘못 생각하고 있는게 아니라면 instantiation binding이 제대로 동작하고 있는 것 같습니다.

호오... 매우 흥미로운 결과입니다. 왜 이 생각을 못했을까요? ^^;

kane wrote:
이제 왜 "int*"일 때는 안됐는가가 문제인데..

http://library.n0i.net/programming/c/cp-iso/template.html 에서 14.6.4 - Dependent name resolution [temp.dep.res]는 다음과 같습니다.

Quote:
-1- In resolving dependent names, names from the following sources are considered:

* Declarations that are visible at the point of definition of the template.
* Declarations from namespaces associated with the types of the function arguments both from the instantiation context (temp.point) and from the definition context.


정의한 순간에 visible하거나 type of argument와 같은 namespace에 있는 이름을 찾는다는 의미인 것 같습니다. (사실 visible의 명확한 의미는 모르겠습니다만.. 대략 그 이전에 선언되었다는 의미로 이해하고 있습니다.)
그렇다면 class C와 foo(C)는 같은 namespace로 처리가 됐는데, int*와 foo(int*)는 같은 namespace로 처리되지 않는게 아닌가 하는 추측이 가능합니다. 그래서 맨 처음 int*의 namespace에 대해서 물어본 건데..
물론 이건 어디까지나 제 추측에 불과합니다. 저도 왜 S<int*> a; 는 에러가 발생하는지 모르겠습니다. comeau가 잘못된 건 아닐까요? :wink:

comp.lang.c++에 이 질문을 올렸더니 두 사람이 답변해 줬습니다. 한 사람은
Comeau의 버그라고 했고, 다른 사람은 Comeau가 맞다고 합니다. 둘 다 뉴스그룹에서는
유명한 고수인데, 이 문제에 관해서는 후자가 더 자세히 알고 있다고 봅니다. 전에도
관련된 문제로 도움을 받은 적이 있고요. 뉴스그룹의 포스팅이 구글에 피딩될 때까지
시간이 좀 걸리는데 나중에 링크를 올리겠습니다.
내용을 요약하면 int나 int* 같은 내장형은 argument dependent lookup(ADL)의
대상이 되지 않기 때문에 제가 처음에 시도한 코드는 에러 나는 것이 맞답니다.
그러나 kane님이 시도한 코드에서 C는 사용자가 정의한 이름이므로 ADL의 대상이
되고, point of instantiation에서 C가 정의된 namespace에 정의된 함수 foo(C)가
있으므로 컴파일이 되는 것이고요.
어지러울 정도로 복잡합니다. ^^; 그래도 이제 좀 가닥이 잡히는군요.
doldori의 이미지

위에서 말한 뉴스그룹 포스팅의 링크입니다.

http://groups.google.co.kr/groups?th=32b0987f9ed0d510

htna의 이미지

kane wrote:
컴파일러 쪽은 모르지만, name lookup을 바꿨다고 컴파일 하는데 큰 이득이 있을지는 의문이네요. 부모 클래스를 뒤지는 수고는 덜겠지만 컴파일 정보의 재사용 여부에 영향을 미칠 문제는 아닐 것 같습니다. (컴파일러 책을 보러 가야하나? -_-;; )
저도 template object 같은게 있으면 좋겠다고 생각한 적이 있습니다만, 제작자들이 "export"를 구현하기 전까지는 어렵지 않을까요.

제가 머 컴파일러 제작하는 그런류의 사람은 아닙니다. (긁적긁적.. ^^)
그냥 간단하게 생각해 본 것입니다.
위와같이 "this->" 혹은 "list<T,_A>::" 와 같은 구문을 적어줌으로 써, global name space의 내용을 참조해야 하는지, 자신이 hierarchy의 내용을 찾아야 하는지를 미리 결정하는것만으로도, 어느정도 template class/function의 프로토타입을 규정할 수 있지 않을까 생각했습니다. 그렇게 된다면, template을 사용하는 시점마다 소스를 만들어 컴파일 하지 않고, template를 정의하는 시점에 template의 프로토타입을 정의/컴파일 하고, 이 정보를 실제 사용할 때/클래스를 정의할 때에 간단하게 hierarchy에 맞는 부분을 연결해서 실제의 클래스의 object file(맞나요?)를 빠르게 만들어 낼 수 있지 않을까.. 그렇게 해서 컴파일 타임을 크게 줄일 수 있지 않을까 생각했기 때문입니다.

template object까지는 아니더라고, "export" 까지는 아니라도... header file로서 template를 관리하는게 아니라, 일종의 object file(*.obj)에 template class/function의 프로토타입 정보를 기록해 놓고만 있어도...

회사에서 기존의 의 프로그램을 undo가 되게 고치는 프로젝트를 진행하다보니, 어쩔수 없이 template를 매우 많이 사용하게 되었고, 그로인해 컴파일타임이 심하게 2배이상 증가하는 결과를 가져온 경험이 있습니다. ( 현재 약 10시간 이상 컴파일 해야합니다. 예전에는 4시간 정도였나.. 갑자기 치매끼가.. ^^;; )
그래서인지 template의 유용성과, 컴파일시간의 문제가 두고두고 고민이 되는 녀석이네요.. ^^;;;
( undo될 수 있는 모든 변수를 사용하는 시점에 template class/function을 간접적으로 통과하도록 했죠.. ^^;; )

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.