const

728x90
반응형

이번 포스트에서 다룰 내용은 다양한 Template에 대해서 공부한다. 이제까지 배운 Template은 Temlate Function밖에 없었지만 이번에는 다양한 Template에 대한 사용법을 알아본다. 먼저 배울 Template은 아래와 같다. 

 

  • Class Template
  • Aliasing Temlate
  • Variable Template

 

 

Class Template (클래스 템플릿)

 

Class template은 우리가 알게 모르게 사용을 많이 한다. STL(Dtandard Template Library) 자체가 Template으로 구성된 라이브러리이다. Class Template도 Template Function과 동일하게 사용을 하면 된다. 필자는 Template에 대해서 공포감을 느끼기 때문에 충분히 이해가 가능하지만 거부감이 든다. 아래는 Template을 이용해서 push와 pop만 가능한 Data Sturcture의 Stack을 만든 예제이다. 

 

이미 다 공부한 내용이라 코드 첨부로 설명을 마친다. 

 

template<typename T>
class Stack
{
public:
	void push(T elem)
	{
		mVec.emplace_back(std::move(elem));
	}
	bool pop(T& elem)
	{
		if (mVec.size() == 0)
			return false;
		elem = mVec[mVec.size() - 1];
		mVec.pop_back();
		return true;
	}
private:
	std::vector<T> mVec;
};

int main()
{
	Stack<std::string> stack;

	stack.push("jiyong");
	stack.push("is");
	stack.push("he");

	std::string n;
	while (stack.pop(n))
	{
		std::cout << n << '\n';
	}
}

 

 

Aliasing Template (별명 템플릿?)

 

Alias는 별명 혹은 별칭이라는 뜻을 가지고 있다. 결국 Aliasing Template은 별명을 가지게 하는 게 Template을 이용해서 별명을 만든다고 생각하면 쉽다. 

 

#include <vector>
#include <array>

template<typename T>
using pretendKeys = std::vector<std::array<T, 64>>;

int main()
{
	/*
	* alias
	* using pretendInt = int;
	* using pretendKeys = std::vector<int*_t, 64>;
	*/
	
	pretendKeys<float> floatKeys;
	//std::vector<std::array<float, 64>> floatKeys
	pretendKeys<double> doubleKeys;
	//std::vector<std::array<double, 64>> doubleKeys
}

 

alias을 만드는 법은 using 키워드를 통해 만들 수 있다. C++03에서는 typedef를 사용했지만 C++11에서부터 using을 사용해서 더 직관적이게 "별명"을 붙일 수 있다. 

 

 

Variable Template (변수 템플릿) C++14

 

먼저 Variable Template을 설명하기 전에 const와 constexpr에 대해서 짧게 설명한다. 

 

int main()
{
    int n = 10;
    const int a = 10 + n;
    
    constexpr int b = 11 + n;	//ERROR 컴파일 타임에 n이 정해지지 않음.

    return 0;
}

 

const와 constexpr 둘 다 상수를 선언하는 키워드이다. 둘의 차이점은 컴파일 상수이냐 런타임 상수이냐의 차이이다. const는 런타임에 초기값이 정해져 있어야 하고 constexpr는 컴파일 타임에 초기값이 정해져 있어야 한다는 차이점이다. 

 

이제 Variable Template (변수 템플릿)에 대해서 공부를 하자. 

 

변수 템플릿도 별거 없다. C++14부터 지원되는 기능이다. 아래 예제를 보고 충분히 이해할 수 있다. 

 

#include <iostream>

template<typename T>
constexpr T number = T(123.123);

int main()
{
    std::cout << number<int>;

    return 0;
}

 

Variable Template으로 number라는 상수를 선언하고 123.123이라는 값으로 초기화를 하였다. 

 

main함수에서 number상수에 Anlge Bracket으로 Type을 int로 명시하여 출력해주면 integer값으로 Casting이 되고 123이 출력이 된다. 

 

 

Ref.

https://www.youtube.com/watch?v=87nJ-3U4LkA&list=PLDV-cCQnUlIb2oezNpNTmxiiX_NibMrlO&index=5 

반응형
728x90
반응형

클래스를 사용하면서 자주 보게 되는 키워드들에 대해서 알아보자. 

 

const

먼저 const는 constant의 줄임말로 상수 취급을 해준다는 말이다. 즉 값을 바꾸는 것을 방지한다고 보면 된다. const 키워드는 C++ 개발을 안전하게 해 준다. 가능하면 붙여줄 수 있는 곳에 다 붙여주는 것이 좋다. 아래 코드는 const의 사용 예제이다. 

#include <iostream>
#include <string>

class Dog
{
public:
    Dog(std::string) : mName{std::move(name)} {};
    void speak() const
    {
        std::cout << mName << std::endl;
    }
private:
    std::string mName;
    
}

int main()
{
    const Dog choco{"choco"};
    choco.speak();
}

Dog클래스의 멤버 함수인 speak() 함수를 보면 오른쪽에 const키워드가 있는 것을 확인할 수 있다. 이는 멤버 함수를 읽기 전용 함수로 만들어주는 키워드 이기 때문에 함수 내부에서 객체의 멤버 변수에 대해서 수정이 불가하다. 또한 main함수에서 객체 자체를 const객체로 선언을 하였기 때문에 객체의 멤버 변수에 대해서 재정의가 불가하다. 당연하게 만약 const로 선언이 된 객체에서 비 const멤버 함수를 호출하는 것은 불가하다. 쉽게 생각하면 애초에 객체부터 상수화 된 객체인데 멤버 함수에서 수정할 여지가 있다면 안되기 때문이다. 

 

하지만, const 멤버 함수에서 멤버 변수에 대한 수정이 가능한 경우가 있다. 바로 mutable키워드이다. 

만약 클래스의 멤버 변수가 mutable로 선언이 된 경우에는 const멤버 함수 내에서 수정이 가능하다.

#include <iostream>
#include <string>

class Dog
{
public:
    Dog(std::string) : mName{std::move(name)} {};
    void speak() const
    {
        mName = "cream";
        std::cout << mName << std::endl;
    }
private:
    mutable std::string mName;
}

int main()
{
    const Dog choco{"choco"};
    choco.speak();
    //cream
}

위와 같이 mutable로 선언된 string객체가 const멤버 함수 speak() 내에서 수정이 된 것을 확인할 수 있다. 하지만, 이렇게 사용 가능한 것임에도 불구하고 mutable키워드로 멤버 변수를 선언하는 것을 지양해야 한다. 왜냐하면 우리가 const키워드를 사용하는 이유는 멤버 변수의 수정을 막기 위함이다. const를 붙여줌으로써 컴파일러가 멤버 변수의 수정이 불가하다는 것을 인지하고 수정이 될 경우 오류가 있다고 알려주지만 mutable의 경우는 const로 선언한 것을 무시를 해주는 것이기 때문에 지양을 해야 한다. 

 

 

explicit

explicit키워드는 C++에서 implicit conversion을 막기 위함에 있다. expllicit키워드는 주로 constructor에서 사용이 된다.

#include <iostream>
#include <string>

class Cat
{
public:
	explicit Cat(int age) : mAge{ age } {};
	Cat(std::string name, int age) : mName{ std::move(name) }, mAge{ age } {};

private:
	int mAge;
	std::string mName;
	mutable std::string changable = "initial";			
};

int main()
{
    Cat choco = 3; //error
    Cat choco{3};
}

 Cat 클래스에서 interger variable을 1개 받는 Constructor를 보게 되면 explicit키워드가 있다. 이 의미는 main함수에서 명확하게 확인할 수 있다. 만약 객체에 integer값은 대입 연산자로 대입을 하게 될 경우 integer 상수 3이 implicit class-type consversion이 일어나게 된다. 이 뜻은 임시 객체에 3이라는 값을 저장하고 다시 임시 객체를 choco객체에 복사를 하괴 되는 과정이 일어난다. 이는 많은 메모리 손실을 야기하므로 explicit 하게 말 그대로 Argument를 명백하게 curly brace에 넣어서 넘겨줘라 라고 생각하면 쉽다. 

 

통상 클래스를 구성할때 Argument가 1개인 Constructor는 explicit키워드를 넣어주어 implicit conversion을 방지하는 것이 좋다. 

반응형

+ Recent posts