template 키워드의 다른 또 다른 목적..


14.2.4
When the name of a member template specialization appears after . or ->
in a postfix-expression, or after :: in a qualified-id that explic-
itly depends on a template-argument (_temp.dep_), the member template
name must be prefixed by the keyword template. Otherwise the name is
assumed to name a non-template. [Example:


class X {
public:
    template<size_t> X* alloc();
    template<size_t> static X* adjust();
};

void f(X* p)
{
    X* p1 = p->alloc<200>();
    // ill-formed: < means less than

    X* p2 = p->template alloc<200>();
    // fine: < starts explicit qualification
    T::adjust<100>();
    // ill-formed: < means less than
    T::template adjust<100>();
    // fine: < starts explicit qualification
}


--end example]


[Programming Language C++ (ISO)]

'Dev > C++' 카테고리의 다른 글

GRETA  (0) 2007.05.14
A non-type template-parameter  (0) 2007.05.14
A member template cannot be virtual  (0) 2007.05.14
sgi STL - Why does Bounds Checker™ say that I have memory leaks?  (0) 2007.05.14
MinGW - Why is my C++ binary so large?  (0) 2007.05.14
A member template cannot be virtual. For example:

class Shape {
  //...
  template virtual bool intersect(const T&) const = 0; // error: virtual template
};

This must be illegal. If it were allowed, the traditional virtual function table technique for implementing virtual function could not be used. The linker would have to add a new entry to the virtual table for class Shape each time someone called intersect() with a new argument type.

- The C++ Programming Language 3rd Edition (Stroustrap)

Why does Bounds Checker™ say that I have memory leaks?

This is not an STL bug. It is an artifact of certain kinds of leak detectors.

In the default STL allocator, memory allocated for blocks of small objects is not returned to malloc. It can only be reused by subsequent allocate requests of (approximately) the same size. Thus programs that use the default may appear to leak memory when monitored by certain kinds of simple leak detectors. This is intentional. Such "leaks" do not accumulate over time. Such "leaks" are not reported by garbage-collector-like leak detectors.

The primary design criterion for the default STL allocator was to make it no slower than the HP STL per-class allocators, but potentially thread-safe, and significantly less prone to fragmentation. Like the HP allocators, it does not maintain the necessary data structures to free entire chunks of small objects when none of the contained small objects are in use. This is an intentional choice of execution time over space use. It may not be appropriate for all programs. On many systems malloc_alloc may be more space efficient, and can be used when that is crucial.

The HP allocator design returned entire memory pools when the entire allocator was no longer needed. To allow this, it maintains a count of containers using a particular allocator. With the SGI design, this would only happen when the last container disappears, which is typically just before program exit. In most environments, this would be highly counterproductive; free would typically have to touch many long unreferenced pages just before the operating system reclaims them anyway. It would often introduce a significant delay on program exit, and would possibly page out large portions of other applications. There is nothing to be gained by this action, since the OS reclaims memory on program exit anyway, and it should do so without touching that memory.

In general, we recommend that leak detection tests be run with malloc_alloc. This yields more precise results with GC-based detectors (e.g. Pure Atria's PurifyTM), and it provides useful results even with detectors that simply count allocations and deallocations.
C++ programs using the Standard Template Library (ie/ #include ) cause a large part of the library to be statically linked into the binary. The need to statically link the stdc++ into the binary is two fold. First MSVCRT.dll does not contain C++ stdlib constructs. Second the legal implications of generating a libstdc++.dll are restricted by the licensing associated with the library. If you wish to keep your file size down use strip to remove debugging information and other verbatim found in the binary.

strip --strip-all SOMEBINARY.exe

왜 C++에는 finally 키워드를 제공하지 않을까? #

아마 java개발자라면 의문시 되는 질문일것이다.
반대로 C++개발자로서는 왜 java나 C# 같은언어에서 저런 키워드를 제공하고 있는것일까 의문이 들수도 있을것이다.


Resource acquisition is initialization #

Stroustrup의 해답은 C++에서는 "finally" 키워드 보다 낳은 테크닉인 RAII(resource acquisition is initialization)가 있기 때문이라는 것이다.

RAII의 핵심은 소멸자에 있다
C++ 에서는 "finally"에서 해야할 동작(메모리, 리소스 해제..)을 각각의 객체의 소멸자에서 처리 할수 있기 때문에 오히려 더 OOP적인 아닌가 생각이 든다.

자기의 뒷처리(?)를 왜 남에게 맡기는가 ....


Why doesn't C++ provide a "finally" construct? #

Because C++ supports an alternative that is almost always better: The "resource acquisition is initialization" technique.

The basic idea is to represent a resource by a local object, so that the local object's destructor will release the resource. That way, the programmer cannot forget to release the resource


- "Bjarne Stroustrup's C++ Style and Technique FAQ"

http://kldp.org/node/27158

위 쓰레드에서 가장 인상 깊은 코드라고 하면 C++ Template Metaprogramming 으로 작성한 코드가 아닐까..

#include <iostream>
using namespace std;


template <int i>
void Say()
{
    Say<i-1>();
    cout << i << ". I will not throw paper airplanes in class" << endl;
}

template <>
void Say<0>() {}


int main()
{
    Say<100>();
}


class template 의 상속을 이용한 코드
아래 코드는 Base 클래스가 먼저 초기화 되야 한다는 규칙을 이용한 코드이다.

#include <iostream>
using namespace std;


template<int i>
struct C : C<i-1>
{
    C() { cout << i << ". I will not throw paper airplanes in class\n"; }
};
template<> struct C<0> {};


int main()
{
    C<100> c;
}


#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <functional>

using namespace std;

#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>

namespace std {
    namespace tr1 = boost;
}


// 테스트용 클래스
class CInt
{
public:
    CInt(int n = 0)
    {
        n_ = n;
    }

    CInt(const CInt &t)
    {
        n_ = t.n_;
    }

    const CInt& operator=(const CInt &t)
    {
        if (this != &t) {
            n_ = t.n_;
        }
        return *this;
    }

    const CInt& operator=(int n)
    {
        n_ = n;
        return *this;
    }

    ~CInt() {}

public:
    void Print(string str) const
    {
        cout << n_ << str;
    }

    int Get() const
    {
        cout << n_;
        return n_;
    }

    operator int() const
    {
        return Get();
    }

   

private:
    int n_;
};


void Write(int n, string str)
{
    cout << n << str;
}
   

int main()
{
    std::vector<int> v;
    std::vector<CInt> vc;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
        vc.push_back(i);
    }

    std::random_shuffle(v.begin(), v.end());
    std::random_shuffle(vc.begin(), vc.end());

    string sep = "-";

    // 기존 C++ 바인딩
    for_each(v.begin(), v.end(), bind2nd(ptr_fun(Write), sep));
    cout << endl;

    // 새로운 C++ 바인딩
    for_each(v.begin(), v.end(), tr1::bind(Write, ::_1, sep));
    cout << endl;

    using boost::lambda::_1;

    // lambda 표현식
    for_each(v.begin(), v.end(), cout << _1 << sep  );
    cout << endl;


    // 기존 C++ 바인딩
    for_each(vc.begin(), vc.end(), bind2nd(mem_fun_ref(&CInt::Print), sep));
    cout << endl;

    // 새로운 C++ 바인딩
    for_each(vc.begin(), vc.end(), tr1::bind(tr1::mem_fn(&CInt::Print), ::_1, sep));
    cout << endl;
}

+ Recent posts