traits

Tags:

EC++ 3rd ed. 보고 만들어봤습니다.

traits라는거는 C++용 compile time type identification 기법입니다. 다시 한번 강조하자면 *compile time* 입니다. Template Meta Programming(TMP)이 있기에 가능한 일이죠. 아마 자바나 C#이라면 컴파일타임에 iterator type 판단해서 적절한 iterate 연산(아래의 예에선 + 와 ++이 예입니다)을 적용하는게 불가능하죠. (물론 Attribute 같은 기법이 있긴 하지만, 그것도 어디까지나 메소드 호출이 hardwired – 한국어로는 뭐라고해야할지;; – 되는건 아니죠.)

한편으로는 간단하게 object hierarchy 써서 해결하면 쉬울걸 왜 이렇게 했을까라는 의문이 드는 것도 사실이고.. 또 한편으로는 STL의 모토에 효율성 – which is not always attainable in Java Foundation Classes(JFC) – 이 한 축을 이루고 있기에 이런 삽질들이 있었던 것 아닌가 하는 생각도 듭니다.

아래 소스는 STL의 advance 알고리즘의 초강력 간단버젼입니다.

#include

using namespace std;

// Tag classes
struct increasable_tag { };
struct addable_tag: public increasable_tag { };

// Traits
template
struct my_traits
{
// get the iterator category type from each class
typedef typename IterT::iterator_category iterator_category;
};

template
struct my_traits // partial specialization for pointers
{
// make pointers addable
typedef addable_tag iterator_category;
};

// Two classes for demo
class one
{
public:
one():val(0) { }

// I am increasable
typedef increasable_tag iterator_category;

one& operator++(int) { val++; return *this; }

int get_val() { return val; }

private:
int val;
};

class two
{
public:
two():val(0) { }

// I am addable
typedef addable_tag iterator_category;

two& operator++(int) { val++; return *this; }
two& operator+(int d) { val += d; return *this; }

int get_val() { return val; }

private:
int val;
};

// General algorithm
template
void add(IterT &t, DistT d)
{
doAdd(t, d, typename my_traits::iterator_category());
}

// Apply ++ operator several times
template
void doAdd(IterT &t, DistT d, increasable_tag)
{
for (int i = 0; i < d; i++) t++; } // Use + operator for efficiency template
void doAdd(IterT &t, DistT d, addable_tag)
{
t = t + d;
}

int main()
{
one o;
two t;
int i = 0;
int *p = &i;

cout << “one: ” << o.get_val() << endl; cout << “two: ” << t.get_val() << endl; cout << “p: ” << p << endl; add(o, 2); add(t, 3); add(p, 4); cout << “one: ” << o.get_val() << endl; cout << “two: ” << t.get_val() << endl; cout << “p: ” << p << endl; return EXIT_SUCCESS; } [/code]

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *