프로그래밍 기초/C++

[C++ 14] 제네릭 프로그래밍 / 추가된 기능과 기억해야 할 내용

niamdank 2022. 5. 26. 11:00

  제네릭 프로그래밍 

함수 템플릿

타입 결정 방법

= 대부분의 경우 암묵적으로 잘 변환되나 int와 unsigned 같이 모호한 경우 명시적으로 결정해 줘야 한다.


template<typename TPara>

TPara max(TPara a, TPara b) { return a > b ? a : b; }

 

unsigned u1 = 2;

int i = 3;

max(u1, i); // 에러 발생!

max(int(u1), i); // Ok

max<int>(u1, i); // Ok


 

자동 리턴 타입

+ 컴파일러에서 리턴 타입도 추론이 가능하게 되었다.


template<typename T, typename U>

inline auto max(T a, U b)

{
    return a > b ? a : b;

}


 

네임 스페이스

네임 스페이스 한정

= 네임 스페이스로 특정 클래스, 변수 등을 선택해 사용할 수 있다.


struct same {};

namespace c1 {

    struct same {};

    namespace c2 {

        struct same {};

        struct csame {

            ::same x; // 전역 same

            c1::same y; // c1의 same

            same z; // c2의 same

        }

    }

}


 

= 네임 스페이스를 숨길 수 있다.


struct same {};

namespace c1 {

    struct same {};

    namespace c2 {

        struct same {};

        namespace c1{}

        struct csame {

            ::same x; // 전역 same

            c1::same y; // 에러 발생, c1이 c2 내부에 선언되었으나 내부의 c1에는 same이 없다.

            same z; // c2의 same

        }

    }

}


 

클래스 템플릿

템플릿 매개변수

= 템플릿에 타입 외에 매개변수를 전달할 수 있다.


template<typename T, int Size>class fsize_vector{    using self = fsize_vector;public:    using value_type = T;

    const static int my_size = Size;

 

    fsize_veoctor(int s = Size) { assert(s == Size); }

    // ...

private:

    T data[my_size];

}

 

fsize_vector<float, 3> v; // 크기가 3인 fsize_vector를 생성한다.


 

타입 추론과 정의

표현식의 타입

= 표현식을 추적하여 적절한 타입을 사용하도록 하는 decltype이 존재한다.


template<typename Vector1, typename Vector2>

auto operator+(const Vector1& v1, const Vector2& v2)

    -> vector<decltype(v1[0] + v2[0])>; // v1[0] + v2[0]를 담을 수 있는 타입을 사용한다.


 

= 긴 표현식에 대해 간편하게 decltype을 사용할 수 있는 decltype(auto)가 존재한다.


decltype(f(g(x, y, z) + 3 * x)) a = f(g(x, y, z) + 3 * x); // 이러한 표현을

decltype(auto) b = f(g(x, y, z) + 3 * x); // 이와 같이 바꿀 수 있다.


 

람다

값에 의한 캡처

= 람다 스코프 외부의 변수나 상수를 값으로 참조할 수 있다. [=]으로 모든 변수를 값으로 참조할 수 있다.


double phi = 2.5;

auto sin_phi = [phi](double x) { return sin(phi * x); };

 

// 캡처해온 값은 람다 내부에서 수정이 불가능하며 수정하려면 mutable 키워드를 붙여줘야 한다.

double phi = 2.5;

auto sin_phi = [phi](double x) mutable { phi += 0.6; return phi; };


 

레퍼런스에 의한 캡처

= 람다 스코프 외부의 변수를 레퍼런스로 참조할 수 있다. [&]로 모든 변수를 레퍼런스로 참조할 수 있다.


double phi = 2.5;

auto pxr = [&phi](double x) { phi += x; };

pxr(1.0); // phi 는 3.5가 된다.


 

제네릭 람다

+ 람다의 인수 타입을 auto로 사용할 수 있게 되었다.


auto pxr = [&phi](auto x) { phi +=x; };