C++11은 C++의 최신버젼입니다.
gcc에서는 -std=c++0x
또는 -std=c++11
을 붙여서 사용할 수 있습니다.
g++ -O2 -o Main -std=c++11 Main.cc
각 컴파일러가 C++11을 어디까지 지원하는지 알려면 아래 링크를 참고하세요.
STL 선언
더 이상 STL을 선언할 때, 공백을 추가하지 않아도 됩니다.
vector<pair<int,int> > a;
vector<pair<int,int>> a;
Initializer Lists
지금까지 vector
, set
과 같은 컨테이너에 초기값을 넣을 때, vector
는 push_back
, set
은 insert
를 사용해야 했습니다.
이제 Initializer List {}
를 이용해서 간단하게 선언할 수 있습니다.
vector<int> primes;
primes.push_back(2);
primes.push_back(3);
primes.push_back(5);
primes.push_back(7);
vector<int> primes = {2, 3, 5, 7};
vector<int> a = {1,2,3,4,5};
pair<string, int> p = {"Year", 2015};
map<string, int> age = { {"Sunyoung", 26}, {"Sangkeun", 26} };
vector<vector<int>> matrix = {{1, 2}, {3, 4}};
vector<pair<int,int>> l = {{1, 2}, {3, 4}, {5, 6}};
vector<pair<int,int>> a;
a.push_back(make_pair(1,2));
a.push_back({1,2});
구조체도 가능합니다!
struct Point {
double x, y;
Point(double x, double y) : x(x), y(y) {}
};
vector<Point> a;
a.push_back(Point(1,2));
a.push_back({1,2});
구조체의 경우에 다음과 같이 초기값을 넣을 수도 있습니다.
struct Point {
double x = 1.0, y = 2.0;
};
tie
pair
에 들어있는 값을 tie
를 이용해 받아올 수 있습니다.
pair<int,int> p = {1, 2};
int a, b;
tie(b,a) = p;
cout << a << ' ' << b << '\n';
tie
를 이용하면 swap
도 간단하게 작성할 수 있습니다.
int a = 10, b = 20;
tie(a,b) = make_pair(b,a);
tie
에서 무시하고 싶은 값이 있으면 ignore
를 이용하면 됩니다.
int a = 10;
tie(a,ignore) = make_pair(20, 30);
min과 max
수 2개, 3개, 4개의 min을 구하는 경우 지금까지는 아래와 같이 작성했습니다.
min(1,2);
min(min(1,2),3);
min(min(1,2),min(3,4));
이제 Initializer List를 이용하면 됩니다!
min(1,2);
min({1, 2, 3});
min({1, 2, 3, 4});
당연히 max
도 Initializer List를 지원합니다.
min과 max를 한 번에 구해야하는 경우에는 minmax
를 사용할 수 있습니다. minmax
는 pair
를 리턴하기 때문에, tie
를 이용해 변수로 받아올 수 있습니다.
int t1, t2;
tie(t1,t2) = minmax({1,2,3});
cout << t1 << ' ' << t2 << '\n';
auto
auto
를 이용해 변수 타입을 생략할 수 있습니다. Python과 같이 동적으로 변수의 타입이 결정되는 것이 아니고, 컴파일을 하면서 변수의 타입을 결정하는 것이기 때문에, auto a;
와 같이 변수 타입을 결정할 수 없는 경우에는 사용할 수 없습니다.
auto a=0, b=1;
auto
를 이용하면 iterator
를 편리하게 사용할 수 있습니다.
vector<int> a = {1,2,3,4,5};
for (vector<int>::iterator it = a.begin(); it != a.end(); it++) {
cout << *it << '\n';
}
위의 소스를 auto를 이용하면
vector<int> a = {1,2,3,4,5};
for (auto it = a.begin(); it != a.end(); it++) {
cout << *it << '\n';
}
가 됩니다!
map<string,pair<int,int>> d = {{"Sunyoung", {1,2}}, {"Startlink",{3,4}}};
for (map<string,pair<int,int>>::iterator it = d.begin(); it != d.end(); it++) {
cout << (it->first) << ' ' << (it->second.first) << ' ' << (it->second.second) << '\n';
}
이렇게 복잡한 for문도
map<string,pair<int,int>> d = {{"Sunyoung", {1,2}}, {"Startlink",{3,4}}};
for (auto it = d.begin(); it != d.end(); it++) {
cout << (it->first) << ' ' << (it->second.first) << ' ' << (it->second.second) << '\n';
}
로 바꿀 수 있습니다.
Range-based for
vector<int> a = {1,2,3,4,5};
for (vector<int>::iterator it = a.begin(); it != a.end(); it++) {
cout << *it << '\n';
}
for (int i=0; i<a.size(); i++) {
cout << a[i] << '\n';
}
for (auto i : a) {
printf("%d\n",i);
}
위의 for
문 3개는 모두 같은 값을 출력하게 됩니다.
set<string> s = {"Choi", "Kim", "Park", "Lee"};
for (set<string>::iterator it = s.begin(); it != s.end(); it++) {
const string &name = *it;
cout << name << '\n';
}
for (const string &name : s) {
cout << name << '\n';
}
for (auto &name: s) {
cout << name << '\n';
}
위의 for
문 3개도 모두 같은 값을 출력하게 됩니다.
Range-based for와 auto
를 잘 활용하면 간결하게 코드를 작성할 수 있습니다. &
를 사용하지 않으면 값복사가 일어나기 때문에 &
를 사용하는 것이 좋습니다.
map<string, int> d = {{"brown",1}, {"red",2}, {"blue",6}};
for (auto &p : d) {
auto &key = p.first;
int val = p.second;
cout << key << ' ' << val << '\n';
}
아래 예시를 살펴봅시다.
for (char c : "RGB") {
// 4번
}
for (char c : string("RGB")) {
// 3번
}
위의 for
는 C언어 문자열을 사용하기 때문에, 마지막 NULL문자까지 c에 받아옵니다. 따라서, 총 4번 수행하게 되고, 아래는 C++ string 이기 때문에, NULL 문자가 없어 3번만 루프를 수행하게 됩니다.
for (auto i : {1,2,3,4}) {
cout << i << '\n';
}
tuple
tuple
은 사용하면 pair
와 같지만, 더 많은 자료를 포함할 수 있습니다.
pair<int,pair<int,int>> p = make_pair(1,make_pair(2,3));
cout << p.first << ' ' << p.second.first << ' ' << p.second.second << '\n';
더 이상 위와 같이 작성할 필요가 없습니다.
tuple<int, int, int> t(1,2,3);
tuple<int, int, int> t2 = make_tuple(1,2,3);
tuple
은 get을 이용해서 받아올 수 있습니다.
tuple<int, int, int> t(1,2,3);
int t1 = get<0>(t);
int t2 = get<1>(t);
int t3 = get<2>(t);
cout << t1 << ' ' << t2 << ' ' << t3 << '\n';
아래와 같은 방식으로는 사용할 수 없습니다.
tuple<int, int, int> t(1,2,3);
for (int i=0; i<3; i++) {
int t = get<i>(t);
}
tuple
도 tie
를 이용할 수 있습니다.
tuple<int, int, int> t(1,2,3);
int t1,t2,t3;
tie(t1,t2,t3) = t;
Lambda
Lambda는 익명 함수 이며, 다음과 같은 형식을 가지고 있습니다.
// [] : captures
// () : parameters
// {} : body
auto f = [](){};
sort
함수를 이용할 때, 지금까지 string
을 역순으로 정렬하는 compare 함수는 다음과 같이 작성했습니다.
bool cmp(const string &u, const string &v) {
return u > v;
}
int main() {
vector<string> v = {"Baekjoon", "Sunyoung", "Choi", "Kim"};
sort(v.begin(),v.end(),cmp);
for (auto &name : v) {
cout << name << '\n';
}
}
Lambda를 사용하면 다음과 같이 작성할 수 있습니다.
int main() {
vector<string> v = {"Baekjoon", "Sunyoung", "Choi", "Kim"};
sort(v.begin(),v.end(),[](const string &u, const string &v) {
return u > v;
});
for (auto &name : v) {
cout << name << '\n';
}
}
Lambda를 이용하는 경우에는 바깥에 있는 변수에 접근을 할 수가 없습니다.
다음과 같이 v
를 p
를 기준으로 정렬하는 경우에는 컴파일 에러를 받게 됩니다.
int main() {
vector<string> v = {"Baekjoon", "Sunyoung", "Choi", "Kim"};
map<string,int> p = {{"Baekjoon", 5},{"Sunyoung", 4}, {"Choi",10}, {"Kim",1}};
sort(v.begin(),v.end(),[](const string &u, const string &v) {
return p[u] > p[v];
});
for (auto &name : v) {
cout << name << '\n';
}
}
[]
를 [&]
로 변경해 바깥에 있는 변수에 접근할 수 있습니다.
int main() {
vector<string> v = {"Baekjoon", "Sunyoung", "Choi", "Kim"};
map<string,int> p = {{"Baekjoon", 5},{"Sunyoung", 4}, {"Choi",10}, {"Kim",1}};
sort(v.begin(),v.end(),[&](const string &u, const string &v) {
return p[u] > p[v];
});
for (auto &name : v) {
cout << name << '\n';
}
}
일반 함수와 같이 사용하려면 auto
를 이용해 Lambda를 받아오고 호출해야 합니다.
int main() {
auto sum = [](int a, int b) { return a+b; };
printf("%d\n",sum(1,2));
}
위의 sum의 자료형은 function<int(int,int)>
입니다. function
은 #include <functional>
에 정의되어 있습니다.
#include <functional>
using namespace std;
int main() {
function<int(int,int)> sum = [](int a, int b) { return a+b; };
printf("%d\n",sum(1,2));
}
Lambda를 이용해 재귀 호출을 하려면, auto
를 사용할 수 없습니다.
int main() {
function<int(int)> f = [&](int x) {
if (x <= 0) return 1;
else return x * f(x-1);
};
printf("%d\n",f(10));
}
emplace
vector<pair<int,int>> a;
a.push_back(make_pair(1,2));
a.emplace_back(1,2);
queue<tuple<int,int,int>> q;
q.push(make_tuple(1,2,3));
q.emplace(3,4,5);
연습 문제 및 풀이
10869번 문제: 사칙연산를 Lambda와 Range-based for를 이용해 풀어볼 수 있습니다.
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
int main() {
int a,b;
cin >> a >> b;
vector<function<int(int,int)>> d;
d.push_back([](int x, int y) {
return x + y;
});
d.push_back([](int x, int y) {
return x - y;
});
d.push_back([](int x, int y) {
return x * y;
});
d.push_back([](int x, int y) {
return x / y;
});
d.push_back([](int x, int y) {
return x % y;
});
for (auto &f : d) {
cout << f(a, b) << '\n';
}
return 0;
}
1076번 문제: 저항을 Initializer List를 이용해서 풀어볼 수 있습니다.
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main() {
map<string, int> d = {
{"black", 0}, {"brown", 1}, {"red", 2},
{"orange", 3}, {"yellow", 4}, {"green", 5},
{"blue", 6}, {"violet", 7}, {"grey", 8},
{"white", 9}
};
string a, b, c;
cin >> a >> b >> c;
long long ans = (long long)(d[a]*10 + d[b]);
for (int k=0; k<d[c]; k++) {
ans *= 10LL;
}
cout << ans << '\n';
return 0;
}
10825번 문제: 국영수를 tuple
과 Lambda를 이용해 간단하게 풀 수 있습니다.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Person {
string name;
int kor, eng, math;
};
int main() {
int n;
cin >> n;
vector<Person> a(n);
for (int i=0; i<n; i++) {
cin >> a[i].name >> a[i].kor >> a[i].eng >> a[i].math;
}
sort(a.begin(), a.end(), [](const Person &u, const Person &v) {
return make_tuple(-u.kor, u.eng, -u.math, u.name) < make_tuple(-v.kor, v.eng, -v.math, v.name);
});
for (Person &p : a) {
cout << p.name << '\n';
}
return 0;
}
국영수 문제는 아래와 같은 비교 함수로도 풀 수 있습니다.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Person {
string name;
int kor, eng, math;
};
int main() {
int n;
cin >> n;
vector<Person> a(n);
for (int i=0; i<n; i++) {
cin >> a[i].name >> a[i].kor >> a[i].eng >> a[i].math;
}
sort(a.begin(), a.end(), [](const Person &u, const Person &v) {
if (u.kor > v.kor) {
return true;
} else if (u.kor == v.kor) {
if (u.eng < v.eng) {
return true;
} else if (u.eng == v.eng) {
if (u.math > v.math) {
return true;
} else if (u.math == v.math) {
return u.name < v.name;
}
}
}
return false;
});
for (Person &p : a) {
cout << p.name << '\n';
}
return 0;
}
댓글 (3개) 댓글 쓰기
sbjwin 8년 전
C++14도 부탁드립니다.
sgchoi5 6년 전
중간에 emplace_back 에 설명이 없어서 찾아봤는데, push_back 보다 쓰기 편하고, 성능이 더 좋다 입니다... 맞나요? : )
void push_back( T&& value );
template< class... Args > void emplace_back( Args&&... args );
sbjwin 6년 전
std::vector의 멤버 함수인 emplace_back은 C++11부터 추가된 멤버 함수로써 push_back과 같이 vector의 요소 끝에 원소를 추가하는 함수입니다. 두 함수의 가장 큰 차이점은, push_back과 같은 삽입 함수들은 삽입할 객체를 받지만 emplace_back과 같은 생성 삽입 함수는 삽입할 객체의 생성자를 위한 인자들을 받아 std::vector 내에서 직접 객체를 생성하여 삽입하므로 임시 객체의 생성과 파괴, 복사(혹은 move)를 하지 않아도 되어 성능상 더 유리하다는 것입니다. 부족하지만 참고되시길...