서의 공간

C++ 키워드 본문

C++/Syntax, Features

C++ 키워드

홍서의 2020. 11. 27. 07:19

Keywords (C++) | Microsoft Docs

 

1. alignas

더보기

정렬을 제어하는 키워드이다. DirectX 프로그래밍을 할 때 보통 상수 구조체의 데이터 멤버를 정렬할 때 쓴다. 이유는 C++에서 구조체를 메모리에 올렸을 때 구조체 멤버들을 정렬하는 규칙이 HLSL의 규칙과 안맞기 때문이다.

HLSL에서 데이터 멤버들을 4차원 벡터단위로 채워 넣되 하나의 멤버가 두 개의 4차원 벡터에 걸쳐 나누어지면 안 된다는 제약을 지키기 위해 여분의 바이트들이 추가된다. 다음 예를 보면,

// HLSL
struct S
{
	float3 Pos;
	float3 Dir;
};

이 구조체를 4차원 벡터에 채워 넣는다면 다음 모습과 같다.

vector 1: (Pos.x, Pos.y, Pos.z, Dir.x)
vector 2: (Dir.y, Dir.z, empty, empty)

여기서 Dir멤버가 vector 1, vector 2에 나뉘어 저장되었음을 알 수 있다. 이는 하나의 멤버가 4차원 벡터들의 경계에 걸치면 안된다는 HLSL의 규칙을 위반한 것이다. HLSL의 규칙에 맞는 채우기 방식은 다음과 같다.

vector 1: (Pos.x, Pos.y, Pos.z, empty)
vector 2: (Dir.x, Dir.y, Dir.z, empty)

이제 이에 대응되는 C++의 구조체의 정의가 다음과 같다고 하자.

// C++
struct S
{
	XMFLOAT3 Pos;
	XMFLOAT3 Dir;
}

여기서 바이트들을 무작정 복사한다면 위에서 본 상황과 마찬가지가 된다. 이런일을 방지하려면 적절하게 여분의 바이트를 채워두어야 한다. 따라서

// C++
struct S
{
	XMFLOAT3 Pos;
    float padding;
    XMFLOAT3 Dir;
    float padding;
}

하지만 여기서 alignas 키워드를 사용하면 간단히 할 수 있다.

// C++
struct S
{
	alignas(16) XMFLOAT3 Pos;
    alignas(16) XMFLOAT3 Dir;
}

2. auto

더보기

변수의 타입을 컴파일러가 자동으로 추론해줌.

// cl.exe /analyze /EHsc /W4
#include <iostream>

using namespace std;

int main( )
{
    int count = 10;
    int& countRef = count;
    auto myAuto = countRef;

    countRef = 11;
    cout << count << " ";

    myAuto = 12;
    cout << count << endl;
}

3. constexpr

더보기

상수표현식이라고 한다. const와 비슷하게 변수에 적용할 수 있다. 상수표현식 변수를 수정하려 하면 컴파일러 오류가 발생한다. const와 차이점은 constexpr은 함수 및 클래스 생성자에도 적용 할 수 있다는 것. constexpr은 값 또는 반환 값이 상수이고 가능한 컴파일 타임에 계산된다. 다음은 예제이다.

// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>

using namespace std;

// Pass by value
constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp2(x * x, n / 2) :
        exp2(x * x, (n - 1) / 2) * x;
}

// Compile-time computation of array length
template<typename T, int N>
constexpr int length(const T(&)[N])
{
    return N;
}

// Recursive constexpr function
constexpr int fac(int n)
{
    return n == 1 ? 1 : n * fac(n - 1);
}

// User-defined type
class Foo
{
public:
    constexpr explicit Foo(int i) : _i(i) {}
    constexpr int GetValue() const
    {
        return _i;
    }
private:
    int _i;
};

int main()
{
    // foo is const:
    constexpr Foo foo(5);
    // foo = Foo(6); //Error!

    // Compile time:
    constexpr float x = exp(5, 3);
    constexpr float y { exp(2, 5) };
    constexpr int val = foo.GetValue();
    constexpr int f5 = fac(5);
    const int nums[] { 1, 2, 3, 4 };
    const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };

    // Run time:
    cout << "The value of foo is " << foo.GetValue() << endl;
}

4. declype

더보기

지정된 표현식의 타입을 알아낸다. auto키워드와 함께 주로 템플릿 라이브러리를 작성할 때 유용하다. 다음은 예제이다.

// decltype_1.cpp
// compile with: cl /EHsc decltype_1.cpp

#include <iostream>
#include <string>
#include <utility>
#include <iomanip>

using namespace std;

template<typename T1, typename T2>
auto Plus(T1&& t1, T2&& t2) ->
   decltype(forward<T1>(t1) + forward<T2>(t2))
{
   return forward<T1>(t1) + forward<T2>(t2);
}

class X
{
   friend X operator+(const X& x1, const X& x2)
   {
      return X(x1.m_data + x2.m_data);
   }

public:
   X(int data) : m_data(data) {}
   int Dump() const { return m_data;}
private:
   int m_data;
};

int main()
{
   // Integer
   int i = 4;
   cout <<
      "Plus(i, 9) = " <<
      Plus(i, 9) << endl;

   // Floating point
   float dx = 4.0;
   float dy = 9.5;
   cout <<
      setprecision(3) <<
      "Plus(dx, dy) = " <<
      Plus(dx, dy) << endl;

   // String
   string hello = "Hello, ";
   string world = "world!";
   cout << Plus(hello, world) << endl;

   // Custom type
   X x1(20);
   X x2(22);
   X x3 = Plus(x1, x2);
   cout <<
      "x3.Dump() = " <<
      x3.Dump() << endl;
}

5. explicit

더보기

explicit 키워드는 클래스 정의에서만 사용할 수 있고 파라미터가 하나뿐인 생성자에서만 의미가 있다. 파라미터의 암묵적 변환을 막는다.

6. extern

더보기

extern 키워드는 명시적으로 외부 링킹할 대상을 선언한다. extern 키워드는 몇몇 특정한 경우에 활용된다. 예를 들어 const나 typedef는 기본적으로 내부 링킹이 적용되나 extern 키워드로 외부 링킹이 적용되게 바꿀 수 있다.

7. mutable

더보기

메서드가 객체의 특정 데이터 멤버를 변경하기는 하지만 논리적으로는 const인 경우가 있다. 즉, 특정 데이터의 변경이 메서드의 사용자 쪽에서 볼 때는 전혀 영향이 없지만, 여하튼 코드 상으로는 변경이기 때문에 컴파일러가 해당 메서드를 const로 선언하지 못하게 할 수 있다. 예를 들어 스프레드시트 프로그램의 사용자 이용 성향을 프로파일링해보기 위해 SpreadsheetCell 클래스의 getValue()나 getString() 메서드에 접근 카운터를 구현했다고 하자. 이러한 카운터는 의미상 객체의 데이터에 변화를 주지 않지만, 컴파일러 측면에서 볼 때는 객체의 데이터 멤버를 변경하는 행위와 구별이 안 된다. 이 때의 해결책이 mutable 키워드이다. mutable 키워드를 접근 카운터 멤버 변수에 적용하면 컴파일러는 해당 변수의 변경이 메서드의 const에 영향을 미치지 않는 것으로 간주한다.

8. noexcept

9. sizeof

10. static_cast, reinterpret_cast, dynamic_cast

더보기

static_cast: 가장 일반적인 타입 변환

reinterpret_cast: static_cast보다 강력하지만 위험한 캐스팅 방법

dynamic_cast: 클래스 계층에 대한 런타임 타입 정보(RunTime Type Information, RTTI) 검사를 수행하영 해당 변환이 적합한 클래스 계층 간 이동인지 확인한다.

11. typedef

12. using

13. virtual

14. volatile

'C++ > Syntax, Features' 카테고리의 다른 글

C++ 복사 생성자와 임시 객체  (0) 2020.12.13
C++ 템플릿  (0) 2020.11.27
C++ STL(Standard Template Library)  (0) 2020.11.27
C++ Standard Library (표준 라이브러리)  (0) 2020.11.27
Comments