반응형
  • 기본적으로 Promise는 함수에 콜백을 전달하는 대신에 콜백을 첨부하는 방식의 객체를 말한다.
  • Promise를 이용하면 콜백함수를 중첩으로 호출해야 할때 피라미드 생성을 피할 수 있다.

기본 Promise 생성

// 비동기 동작이 필요한 Promise 정의
var promise1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 3000);
});

// Promise 함수 실행
promise1.then(function(value) {
  console.log(value);
  // expected output: "foo"
});

console.log(promise1);
// expected output: [object Promise]

 

일반적인 콜백 함수 호출

function successCallback(result) {
  console.log("Audio file ready at URL: " + result);
}

function failureCallback(error) {
  console.log("Error generating audio file: " + error);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);

콜백 중첩 호출

  • 피라미드 패턴으로 가독성 X
doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log('Got the final result: ' + finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);

 

Promise 호출

function successCallback(result) {
  console.log("Audio file ready at URL: " + result);
}

function failureCallback(error) {
  console.log("Error generating audio file: " + error);
}

const promise = createAudioFileAsync(audioSettings); 
promise.then(successCallback, failureCallback);

 

Promise 중첩 호출

  • then 에 넘겨지는 인자는 선택적(optional)
  • catch(failureCallback)는 then(null, failureCallback) 의 축약
doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);


// 축약 표현식으로 변경시
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
  console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
반응형

반응형
  • Lazy Instantiation
    • 사용되지 않은 템플릿 클래스는 인스턴스화 되지 않음
    • 사용되지 않은 템플릿 클래스의 멤버 함수도 인스턴스화 되지 않음
    • 사용되지 않은 템플릿 클래스의 static 함수도 인스턴스화 되지 않음
    • 사용되지 않은 전역 템플릿 변수도 인스턴스화 되지 않음
template<typename T> class A
{
    T data;
public:
    void foo(T n) { *n = 10; } // 참조 오류 코드
};

int main()
{
    A<int> a;
    // a.foo(1); 템플릿의 멤버 함수가 호출되지 않는다면 인스턴스화 되지 않으므로 컴파일 성공
}
struct Resource1
{
    Resource1() { cout << "Resource1()" << endl; }
    ~Resource1() { cout << "~Resource1()" << endl; }
};

struct Resource2
{
    Resource2() { cout << "Resource2()" << endl; }
    ~Resource2() { cout << "Resource2()" << endl; }
};

template<typename T> struct Test
{
    Resource1 res1; // 클래스내 메모리 할당이 필요하므로 인스턴스화됨
    static Resource2 res2; // static 멤버는 별도 메모리 할당으로 인스턴스화 되지 않음
};
template<typename T> Resource2 Test<T>::res2; // 사용되지 않아서 인스턴스화 되지 않음

int main()
{
    cout << "main" << endl; // 1. 메인 출력
    Test<int> t; // 2. Resource1 생성자 출력
}

 

  • if 문과 Lazy Instantiation
    • if 문은 "실행시간 조건문"으로 컴파일 시간에 조건이 false로 결정되어도 if 문에 있는 코드는 항상 사용되는 것으로 간주함
    • C++17 if constexpr는 "컴파일 시간 조건문"으로 조건이 false로 결정되면 if 문에 포함된 코드는 사용되지 않는 것으로 간주됨
    • 동일한 이름의 함수가 여러개 있을 때 어떤 함수를 호출할 지 결정하는 것은 컴파일 시간에 결정되므로 선택되지 않은 함수가 템플릿이라면 인스턴스화 되지 않음
template<typename T> void foo(T n)
{
    *n = 10; // 참조 오류 코드
}

int main()
{
    if(false) // 런타임 조건식이므로 foo는 인스턴스화 됨
        foo(0);

    if constexpr ( false ) // C++17의 컴파일타임 조건식이므로 foo는 인스턴스화 되지 않음
        foo(0);
}
반응형

반응형
  • 함수와 템플릿
    • square는 함수가 아닌 함수 템플릿, square<int>가 함수
template<typename T> T square(T a)
{
    return a * a;
}

int main()
{
    printf("%p\n", &square); // 함수 템플릿의 주소 출력 error
    printf("%p\n", &square<int>); // int 버전 함수 주소 출력 ok
    printf("%p\n", static_cast<int(*)(int)>(&square)); // int 버전 함수로 캐스팅후 주소 출력 ok

    auto p = &square; // 함수 템플릿 주소는 담을 수 없으므로 error
    auto p = &square<int>; // int 버전 함수 주소 담기 ok
    auto p = static_cast<int(*)(int)>(&square); // int 버전 함수 주소 담기 ok
}

 

  • 템플릿의 구현부는 항상 헤더파일에 함께 제공하여야 함
    • 아래와 같이 함수 템플릿을 헤더와 소스파일로 분리하면 main에서 square 호출 시 실제 Lib.h 헤더파일만 참고하므로 템플릿을 기반으로 실제 int형 함수 생성이 필요한데 생성할 구현부 확인이 불가능하여 에러 발생
// 함수 템플릿을 선언과 구현부를 헤더와 소스파일로 분리한 잘못 구현한 예
////////////////////////////////////////
// Lib.h
int add(int a, int b);
template<typename T> T square(T a);
////////////////////////////////////////

////////////////////////////////////////
// Lib.cpp
int add(int a, int b) 
{
    return a + b;
}

template<typename T> T square(T a)
{
    return a * a;
}
////////////////////////////////////////

////////////////////////////////////////
// main.cpp
#include "Lib.h"
int main()
{
    add(1, 2);
    square(3);
}
////////////////////////////////////////
// 함수 템플릿을 헤더 파일로 모두 제공한 예
////////////////////////////////////////
// Lib.h
int add(int a, int b);
template<typename T> T square(T a)
{
    return a * a;
}
////////////////////////////////////////

////////////////////////////////////////
// Lib.cpp
int add(int a, int b) 
{
    return a + b;
}
////////////////////////////////////////

////////////////////////////////////////
// main.cpp
#include "Lib.h"
int main()
{
    add(1, 2);
    square(3);
}
////////////////////////////////////////
반응형

반응형

함수 템플릿 사용시 컴파일러에 의한 타입 추론을 막는 테크닉

  • 함수 템플릿 사용시 사용자가 반드시 타입을 전달하도록 하고 싶을때 사용하는 기법
    • C++17 이하에서 클래스 템플릿이 타입 추론을 지원하지 않는 성격을 활용
    • 함수 템플릿 파라미터로 클래스 템플릿을 사용
    • 컴파일러에 의한 타입 추론이 원하지 않는 타입으로 추론되는 경우 방지
template<typename T> struct identity
{
    typedef T type;
};

template<typename T> void foo(T a) {}
template<typename T> void goo(typename identity<T>::type a) {}

int main()
{
    identity<int>::type n; // int

    foo(3); // ok
    foo<int>(3); // ok

    goo(3); // error, 클래스 템플릿의 인자는 추론이 불가하므로 C++17 이하
    goo<int>(3); // ok
}
반응형

반응형
  • C++17 이전까지는 클래스 템플릿은 함수 인자를 통해 타입을 추론 할 수 없기 때문에, 클래스 템플릿 사용이 복잡하고 불편함
  • "클래스 템플릿의 객체를 생성하는 함수 템플릿"을 사용
    • 함수 템플릿은 함수 인자를 통해서 컴파일러가 추론(Argument Type Deduction)할 수 있는 특징 활용 기법
  • make_pair(), make_tuple()등의 make 계열 함수, STL 삽입반복자등
#include <iostream>

template<typename T> void foo(T a) {}
template<typename T, typename U> struct pair
{
    T first;
    U second;
    pair(const T& a, const U& b) : first(a), second(b) {}
};

template<typename T, typename U>
pair<T, U> make_pair(const T& a, const U& b)
{
    return pair<T, U>(a, b);
}

int main()
{
    pair<int, double> p(1, 3.4);
    foo(p);
    foo(pair<int, double>(1, 3.4)); // 클래스 템플릿은 꼭 타입 전달 필요
    foo(make_pair(1, 3.4)); // 함수 템플릿으로 타입 추론하여 클래스 객체 생성
}
반응형

반응형

다운로드 받을 파일 타입(Mimetype) 구분 방법

import mimetypes

mimetypes.guess_type('test.png')  # return ('image/png', None)

 

 

    import mimetypes
    import urllib
    
    
    file_name = urllib.parse.quote(file_info.file_name.encode('utf-8'))

    if os.path.exists(file_path):
        with open(file_path, 'rb') as fh:
            response = HttpResponse(fh.read(), content_type=mimetypes.guess_type(file_path)[0])
            response['Content-Disposition'] = 'attachment;filename*=UTF-8\'\'%s' % file_name
            return response

 

반응형

반응형

템플릿 인자 타입 추론(Template Argument Type Deduction)

  • 사용자가 템플릿 인자를 명시적으로 지정하지 않은 경우 컴파일러가 인자를 보고 추론(deduction)하는 것
  • 타입을 결정하는 방식(type deduction rule  참고)
template<typename T> T square(T a)
{
    return a * a;
}

int main()
{
    square<int>(3);
    square(3); // 인자 타입 추론(int)
    square(3.3); // 인자 타입 추론(double)
}

 

클래스 템플릿 인자 타입 추론(Class Template Argument Type Deduction)

  • C++ 17부터 지원
  • 생성자를 통한 타입 결정
  • 사용자가 "user define deduction guide" 제공
#include <list>
using namespace std;

template<typename T> class Vector
{
    T* buff;
public:
    Vector() {} // #1 타입 추론이 불가능 할경우 유저 정의 추론 가이드 필요
    Vector(int sz, T initValue) {}

    template<typename C> Vector(C& c) {} // #2 타입 추론이 불가능 할경우 유저 정의 추론 가이드 필요
};

//유저 정의 추론 가이드 제공 필요(user define deduction guide)
Vector()->Vector<int>; // #1 Vector 기본 생성자 호출 시 int로 타입 추론 가이드
template<typename C> Vector(C& c)->Vector<typename C::valuetype >; // #2 int

int main()
{
    Vector<int> v1(10, 3);

    list<int> s = { 1,2,3 }; // list s = { 1,2,3 }; C++17 Style

    Vector v4(s);
}
반응형

반응형

Template Instantiation

  • 컴파일러가 함수(클래스) 틀(Template)로 부터 실제 C++ 함수(클래스)를 만들어 내는 과정
template<typename T>
T square(T a) // template 기준 int squre(int a), double square(double a) 실제 함수를 만드는 과정
{
    return a * a;
}

int main()
{
    square(3);
}

 

  • 명시적 인스턴스화(Explicit Instantiation)
    • 템플릿을 사용해서 특정 타입의 함수(클래스)를 생성해 달라고 명시적으로 지시하는 것
    • 함수/클래스 선언과 유사한 모양으로 작성
template<typename T> class Test
{
public:
    void foo() {}
    void goo() {}
};
template class Test<int>; // 명시적 인스턴스화(클래스 템플릿), foo, goo 모두 인스턴스화
template void Test<int>::foo(); // 명시적 인스턴스화(클래스 템플릿), foo 부분 인스턴스화

template<typename T> T square(T a)
{
    return a * a;
}
template int square<int>(int); // 명시적 인스턴스화(함수 템플릿)
template int square<>(int); // 명시적 인스턴스화(템플릿) 축약 표현
template int square(int); // 명시적 인스턴스화(템플릿) 축약 표현

int main()
{
}

 

  • 암시적 인스턴스화(Implicit Instantiation)
    • 명시적 인스턴스화를 하지 않고 템플릿을 사용하는 경우, 암시적으로 인스턴스화가 발생함
    • 사용 방법
      • 사용자가 타입을 직접 전달하는 방법
      • 함수 인자를 통해서 컴파일러가 타입을 추론하는 방법(template argument type deduction)
      • 클래스 생성자를 통한 컴파일러 타입 추론하는 방법(class template type deduction, C++17이상)
    • 클래스 템플릿의 경우 사용하지 않는 멤버 함수는 인스턴스화 되지 않음(lazy instantiation)
template<typename T> class Test
{
public:
    void foo() {}
    void goo() {}
};
//template class Test<int>; // 명시적 인스턴스화(클래스 템플릿), foo, goo 모두 인스턴스화

template<typename T> T square(T a)
{
    return a * a;
}
//template int square<int>(int); // 명시적 인스턴스화(함수 템플릿)

int main()
{
    int n1 = square(3); // 암시적 인스턴스화(인자를 통한 컴파일러 타입 추론)
    int n2 = square<int>(3); //암시적 인스턴스화

    Test<int> t1; // 암시적 인스턴스화(클래스)
    t1.foo(); // Test 클래스의 foo 멤버함수만 사용하므로 foo 멤버함수만 인스턴스화됨(goo x)
}

 

  • 어셈블리 코드 확인
    • cl file.cpp /FAs -> file.asm 파일 생성
    • g++ file.cpp -S -> file.s 파일 생성
  • 컴파일러 옵션 사용 g++, clang++(중간 언어로 확인 가능)
    • g++ -fdump-tree-original file.cpp -> file.cpp.003t.original
    • clang++ -Xclang -ast-print -fsyntax-only file.cpp
반응형

+ Recent posts