[STL] c++ std::string, complex, bitset, pair 기초 문법
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 에 존재한다.
실제 사용시 정의하지 않고 바로 사용하면 된다.