PROGRAMMING/C++

[STL] c++ std::string, complex, bitset, pair 기초 문법

KIM DEON 2020. 7. 12. 22:04

std::string

STL string을 이용한 문자열 처리

 

c header를 사용할 때의 strcpy(), strcmp() 의 함수를 사용할 필요 없이,

일반 변수와 같이 유사하게 코드를 작성할 수 있다. 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h> //c header
#include <string> //STL string, strcpy(), strcmp()등 사용할 필요없이 일반 변수와 유사하게 작성
using namespace std;

int main() {
	string s1 = "hello";
	char s2[10];
	
	strcpy(s2, s1.c_str()); //c_str() const char* 로의 반환, 반환된 문자열을 널 문자로 끝나는 문자열

	string s3 = "3.4";
	double d = stod(s3); //string to double
	// int변환 -> stoi, stol, stoll 등
	// float변환 -> stof, stod, stold

	string s4 = to_string(5.4); //double to string

	cout << s4 << endl;
}

사용자 정의 literal

 

다음과 같이 함수를 정의 후 호출했을 때, hello라는 문자열은 string도 될 수 있고 

char* 로 받을 수도 있다.

이때 둘 중 char*을 받는 함수가 우선시되어 호출되는데,

"hello"는 char 배열일 것이고, char 배열은 char 포인터로 암시적 형변환이 가능하기 때문이다.

#include <iostream>
#include <string>
using namespace std;

void foo(string s) { cout << "string" << endl; }
void foo(const char* s) { cout << "char*" << endl; }

int main() {
	foo("hello");
}

string을 받는 foo 함수를 호출하기 위해, "hello" 를 string 객체로 만들어 줄 수 있다.

이때 사용되는 것이 user defined literal, 사용자 정의 literal이다.

#include <iostream>
#include <string>
using namespace std;

void foo(string s) { cout << "string" << endl; }
void foo(const char* s) { cout << "char*" << endl; }

int main() {
	foo("hello"s); //string
}

 

위와 같이 literal 뒤에 접미사를 붙여 객체를 만든다.

string을 받는 string 함수가 호출되어, "string"이 호출된다. 

 

std 전체를 가져오는 namespace를 사용하는 대신, 

literal 을 가져오는 namespace를 다음과 같이 사용할 수 있다.

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;
using namespace std::string_literals;
using namespace std::literals;

void foo(string s) { cout << "string" << endl; }
void foo(const char* s) { cout << "char*" << endl; }

int main() {
	foo("hello"s);
}

string literal을 사용하려면 std::string_literals namespace를 선언해주면 된다.

또 다른 literal 까지 모두 사용하고 싶으면, std::literals 를 선언해준다. 

전체 listerals namespace 선언시, 다음과 같이 complex 객체도 사용 가능하다.

#include <iostream>
#include <string>
#include <complex>

using std::cout;
using std::endl;
using std::string;
using namespace std::literals;

int main() {
	std::complex<double> c = 3i;
}

 


std::complex

복소수 클래스

complex 헤더를 추가하여 사용

 

실수부를 리턴하는 real(), 허수부를 리턴하는 imag() 등 멤버함수를 사용할 수 있다.

또한 sin(), cos() 등 복소수 관련 non member 수학 함수를 제공한다.

 

복소수 클래스는 타입 double, float, long double 만 사용가능하다.

complex<double>, complex<float>, complex<long double> 

 

#include <iostream>
#include <complex>
using namespace std;

int main() {
	complex<double> c1(1, 0);

	cout << c1 << endl;

	cout << c1.real() << endl; //1
	cout << c1.imag() << endl; //0

	complex<double> c2 = sin(c1);
	cout << c2 << endl;

	complex<float> c5(3); //3,0
	complex<float> c6(3, 1); //3,1
	complex<float> c7(3if); //literal 객체 -> 0,3

	cout << c5 << endl;
	cout << c7 << endl;
}

 


std::bitset

bit 관리 클래스

bitset 헤더를 추가하여 사용

 

간단한 선언 및 형변환 예제이다.

#include <iostream>
#include <bitset>
#include <string>
using namespace std;

int main() {
	//bitset<8> b1; //0
	//bitset<8> b1 = 0xf0; //11110000
	bitset<8> b1 = 0b11110000;

	cout << b1 << endl; //11110000

	//형변환 가능
	string s = b1.to_string();
	unsigned long n = b1.to_ulong();

	cout << s << endl; //11110000 (string)
	cout << n << endl; //240
}

각 비트 접근 함수 예제이다. (주석 참고)

set, reset, [] 연산, flip 사용 가능하다.

#include <iostream>
#include <bitset>
#include <string>
using namespace std;

int main() {
	//bitset<8> b1; //0
	//bitset<8> b1 = 0xf0; //11110000
	bitset<8> b1 = 0b11110000;

	cout << b1 << endl; //11110000

	b1.set(); //모두 1로
	b1.reset(); //모두 0으로

	b1.set(1); // 0000 0010
	b1[2] = 1; // 0000 0110
	b1[0].flip(); // 0000 0111 
}

조사 함수 예제이다. (주석 참고)

#include <iostream>
#include <bitset>
#include <string>
using namespace std;

int main() {
	bitset<8> b1 = 0b00000111;

	if (b1.test(1) == true) {
		//b1[1] 이 1인가
	}
	if (b1[1] == true) {
		//b1[1] 이 1인가
	}
	if (b1.none() == true) {
		//모든 bit가 0인가
	}
	if (b1.all() == true) {
		//모든 bit가 1인가
	}

	int n2 = b1.count(); //1의 개수
	cout << n2 << endl; //3
}

&, |, ^ 비트 연산 예제이다.

#include <iostream>
#include <bitset>
#include <string>
using namespace std;

int main() {
	bitset<8> b1 = 0b00001111;
	bitset<8> b2 = 0b11110000;
	bitset<8> b3 = b1 | b2;

	cout << b3 << endl; //11111111

}

std::pair

서로 다른 타입의 객체를 2개  보관하는 타입

<utility> 헤더를 추가하여 사용

(utility를 포함하지 않더라도 대부분의 컴파일러에서 pair 사용가능 (iostream에 포함))

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <utility>
using namespace std;

int main() {
	pair<int, double> p1(1, 3.4);
	cout << p1.first << endl; //1
	cout << p1.second << endl; //3.4
}

 

pair을 이용해 return 값이 2개인 함수를 정의할 수 있다.

#include <iostream>
#include <utility>
using namespace std;

pair<int, double> foo() {
	return pair<int, double>(1, 3.4);
}

int main() {
	pair<int, double> p1 = foo();
	cout << p1.first << endl;
}

make_pair

pair를 만드는 helper 함수이다.

 

pair를 인자로 전달 받는 함수를 정의

#include <iostream>
#include <utility>
using namespace std;

//pair를 인자로 전달 받는 함수
template<typename T> void foo(T p) {
	cout << p.first << "," << p.second << endl;
}

int main() {
	pair<int, double> p1(1, 3.4);
	foo(p1);//1,3.4

	//임시 객체 만들어 전달
	foo(pair<int, int>(1, 1));//1,1
}

위 같이 template인자를 보낼때, 바로 pair를 보내지 않고 함수 템플릿을 만들어 사용한다.

함수 템플릿은 클래스 템플릿과 달리 템플릿 인자를 생략할 수 있다. 

그러면 type을 추가하지 않고 사용할 수 있다.

(c++17 부터는 클래스 템플릿도 인자를 생략할 수 있다.)

#include <iostream>
#include <utility>
using namespace std;

//pair를 인자로 전달 받는 함수
template<typename T> void foo(T p) {
	cout << p.first << "," << p.second << endl;
}

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

int main() {
	foo(make_pair(1, 1));
}

 

위에서 정의한 make_pair 함수는 이미 c++ 표준 stl 에 존재한다.

실제 사용시 정의하지 않고 바로 사용하면 된다.