일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 유니티슈팅게임
- 안드로이드스튜디오
- semaphore
- C++
- 유니티
- mutex
- list
- Unity
- Vector
- StartActivityForResult
- 스핀락
- unityAR
- NotFoundException: String resource ID #0x0
- map
- 바이너리세마포
- ARface
- photon
- 포톤
- Java
- SpinLock
- 게임개발
- 세마포
- unorderedset
- registerForActivityResult
- 뮤텍스
- 광유다
- 지크슈
- dependencyResilutionManagement
- 동기화
- unorderedmap
- Today
- Total
와와
씹어먹는 C++ 공부하기 (9~) 본문
9-1. 코드를 찍어내는 틀 - C++ 템플릿(template)
C++ 템플릿 (template)
class Vector {
std::string* data;
int capacity;
int length;
public:
// 생성자
Vector(int n = 1) : data(new std::string[n]), capacity(n), length(0) {}
// 맨 뒤에 새로운 원소를 추가한다.
void push_back(std::string s) {
if (capacity <= length) {
std::string* temp = new std::string[capacity * 2];
for (int i = 0; i < length; i++) {
temp[i] = data[i];
}
delete[] data;
data = temp;
capacity *= 2;
}
data[length] = s;
length++;
}
// 임의의 위치의 원소에 접근한다.
std::string operator[](int i) { return data[i]; }
// x 번째 위치한 원소를 제거한다.
void remove(int x) {
for (int i = x + 1; i < length; i++) {
data[i - 1] = data[i];
}
length--;
}
// 현재 벡터의 크기를 구한다.
int size() { return length; }
~Vector() {
if (data) {
delete[] data;
}
}
};
과 같이 String 데이터를 저장하는 Vector 클래스가 있다.
String 말고도 int, char 등의 데이터를 저장하는데도 쓰고 싶다면 템플릿을 사용하면 됨.
T 라는 타입의 객체들을 보관하는 Vector 클래스는 다음과 같다.
// 템플릿 첫 활용
#include <iostream>
#include <string>
template <typename T> //아래에 정의되는 클래스에 대해 템플릿을 정의
class Vector {
T* data;
int capacity;
int length;
public:
// 생성자
Vector(int n = 1) : data(new T[n]), capacity(n), length(0) {}
// 맨 뒤에 새로운 원소를 추가한다.
void push_back(T s) {
if (capacity <= length) {
T* temp = new T[capacity * 2];
for (int i = 0; i < length; i++) {
temp[i] = data[i];
}
delete[] data;
data = temp;
capacity *= 2;
}
data[length] = s;
length++;
}
// 임의의 위치의 원소에 접근한다.
T operator[](int i) { return data[i]; }
// x 번째 위치한 원소를 제거한다.
void remove(int x) {
for (int i = x + 1; i < length; i++) {
data[i - 1] = data[i];
}
length--;
}
// 현재 벡터의 크기를 구한다.
int size() { return length; }
~Vector() {
if (data) {
delete[] data;
}
}
};
이런식으로 원하는 자료형으로 객체를 생성해주면 된다
Vector<int> int_vec;
Vector<string> string_vec;
템플릿 특수화
template <typename A, typename B, typename C>
class test {};
이렇게 클래스 템플릿이 정의되어 있을 때
특정 자료형의 경우에 객체를 따로 처리하고 싶을 수 있다.
그럴 땐
template <typename C> //A = int, B = string, C=C 인 경우
class test<int, string, C> {};
template <> //int 타입을 전달받은 경우
class test<int> {};
이렇게 지정해주면 된다.
이게 가능하다면
다음과 같이 bool 타입을 넘겨 받을 때 비트 연산을 통해 메모리 효율을 높힐 수 있음
template <>
class Vector<bool> {
unsigned int* data;
int capacity;
int length;
public:
typedef bool value_type;
// 생성자
Vector(int n = 1)
: data(new unsigned int[n / 32 + 1]), capacity(n / 32 + 1), length(0) {
for (int i = 0; i < capacity; i++) {
data[i] = 0;
}
}
// 맨 뒤에 새로운 원소를 추가한다.
void push_back(bool s) {
if (capacity * 32 <= length) {
unsigned int* temp = new unsigned int[capacity * 2];
for (int i = 0; i < capacity; i++) {
temp[i] = data[i];
}
for (int i = capacity; i < 2 * capacity; i++) {
temp[i] = 0;
}
delete[] data;
data = temp;
capacity *= 2;
}
if (s) {
data[length / 32] |= (1 << (length % 32));
}
length++;
}
// 임의의 위치의 원소에 접근한다.
bool operator[](int i) { return (data[i / 32] & (1 << (i % 32))) != 0; }
// x 번째 위치한 원소를 제거한다.
void remove(int x) {
for (int i = x + 1; i < length; i++) {
int prev = i - 1;
int curr = i;
// 만일 curr 위치에 있는 비트가 1 이라면
// prev 위치에 있는 비트를 1 로 만든다.
if (data[curr / 32] & (1 << (curr % 32))) {
data[prev / 32] |= (1 << (prev % 32));
}
// 아니면 prev 위치에 있는 비트를 0 으로 지운다.
else {
unsigned int all_ones_except_prev = 0xFFFFFFFF;
all_ones_except_prev ^= (1 << (prev % 32));
data[prev / 32] &= all_ones_except_prev;
}
}
length--;
}
// 현재 벡터의 크기를 구한다.
int size() { return length; }
~Vector() {
if (data) {
delete[] data;
}
}
};
함수 템플릿 (Function template)
template <typename Cont>
void bubble_sort(Cont& cont) {
for (int i = 0; i < cont.size(); i++) {
for (int j = i + 1; j < cont.size(); j++) {
if (cont[i] > cont[j]) {
cont.swap(i, j);
}
}
}
}
클래스 템플릿처럼 함수 템플릿도 만들 수 있음
함수 객체 (Functor)
bubble_sort 함수에서 오름차순, 내림차순 정렬을 가능하게 해보자.
template <typename Cont, typename Comp>
void bubble_sort(Cont& cont, Comp& comp) {
for (int i = 0; i < cont.size(); i++) {
for (int j = i + 1; j < cont.size(); j++) {
if (!comp(cont[i], cont[j])) {
cont.swap(i, j);
}
}
}
}
struct Comp1 {
bool operator()(int a, int b) { return a > b; }
};
struct Comp2 {
bool operator()(int a, int b) { return a < b; }
};
Comp 라는 클래스를 템플릿 인자로 받고, 함수 자체도 Comp 객체를 따로 받는다.
if 문에서 마치 함수를 호출하는 것 처럼 사용되는데, cont[i] 와 cont[j] 를 받아서 내부적으로 크기 비교를 수행한 뒤에 그 결과를 리턴함. comp 는 함수가 아니라 객체 이고, Comp 클래스에서 () 연산자를 오버로딩한 버전
Comp1 과 Comp2 객체들은 bubble_sort 함수 안에서 마치 함수인양 사용되는데
if (!comp(cont[i], cont[j])) {
이렇게, 함수는 아니지만 함수 인 척을 하는 객체를 함수 객체 (Function Object), 혹은 줄여서 Functor 라고 한다.
타입이 아닌 템플릿 인자 (non-type template arguments)
#include <iostream>
template <typename T, int num>
T add_num(T t) {
return t + num;
}
int main() {
int x = 3;
std::cout << "x : " << add_num<int, 5>(x) << std::endl;
}
이처럼 템플릿 인자로 타입이 아닌 것들을 전달할 수 있다.
#include <iostream>
#include <array>
template <typename T>
void print_array(const T& arr) {
for (int i = 0; i < arr.size(); i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
int main() {
std::array<int, 5> arr = {1, 2, 3, 4, 5};
std::array<int, 7> arr2 = {1, 2, 3, 4, 5, 6, 7};
std::array<int, 3> arr3 = {1, 2, 3};
print_array(arr);
print_array(arr2);
print_array(arr3);
}
디폴트 템플릿 인자
#include <iostream>
#include <string>
template <typename T>
struct Compare {
bool operator()(const T& a, const T& b) const { return a < b; }
};
template <typename T, typename Comp = Compare<T>>
T Min(T a, T b) {
Comp comp;
if (comp(a, b)) {
return a;
}
return b;
}
int main() {
int a = 3, b = 5;
std::cout << "Min " << a << " , " << b << " :: " << Min(a, b) << std::endl;
std::string s1 = "abc", s2 = "def";
std::cout << "Min " << s1 << " , " << s2 << " :: " << Min(s1, s2)
<< std::endl;
}
= (디폴트 값)
으로 인자의 디폴트 값을 정해줄 수 있다.
9-2. 가변 길이 템플릿 (Variadic template)
가변 길이 템플릿 (variadic template)
임의의 개수와 타입의 인자를 받을 수 있는 템플릿을 만드는 기능 ( C++11 부터 도입 )
- 템플릿 파라미터 팩(parameter pack)
typename... Types
- 함수 파라미터 팩
Types... args
- 문법
template <typename T, typename... Types>
void function(T first, Types... rest) {
// 함수 본문
}
예제
template <typename T>
void print(T arg) {
std::cout << arg << std::endl;
}
template <typename T, typename... Types>
void print(T arg, Types... args) {
std::cout << arg << ", ";
print(args...);
}
여기서
print(1, 3.1, "abc")
이러한 형태로 print를 한다고 하면
아래와 같은 형태의 print 가 재귀적으로 호출된다.
void print(int arg, double arg2, const char* arg3) {
std::cout << arg << ", ";
print(arg2, arg3);
}
void print(double arg, const char* arg2) {
std::cout << arg << ", ";
print(arg2);
}
void print(const char* arg) {
std::cout << arg << std::endl;
}
문자열 더하기
아래와 같은 문자열 더하기는 더할 때마다 메모리 할당이 발생한다.
concat = s1 + s2 + s3;
concat = s1.operator+(s2).operator+(s3);
가변 길이 템플릿을 이용해 문자열의 길이를 먼저 구해 메모리를 할당하고, 문자열을 붙여보자!
1. 문자열 길이 구하기
//문자열 길이 구하기
size_t GetStringSize(const char* s) { return strlen(s); }
size_t GetStringSize(const std::string& s) { return s.size(); }
template <typename String, typename... Strings>
size_t GetStringSize(const String& s, Strings... strs) {
return GetStringSize(s) + GetStringSize(strs...);
}
2. StrCat
template <typename String, typename... Strings>
std::string StrCat(const String& s, Strings... strs) {
// 먼저 합쳐질 문자열의 총 길이를 구한다.
size_t total_size = GetStringSize(s, strs...);
// reserve 를 통해 미리 공간을 할당해 놓는다.
std::string concat_str;
concat_str.reserve(total_size);
concat_str = s;
// concat_str 에 문자열들을 붙인다.
AppendToString(&concat_str, strs...);
return concat_str;
}
3. 문자열 붙이기
void AppendToString(std::string* concat_str) { return; }
template <typename String, typename... Strings>
void AppendToString(std::string* concat_str, const String& s, Strings... strs) {
concat_str->append(s);
AppendToString(concat_str, strs...);
}
평균 구하기
#include <iostream>
// 재귀 호출 종료를 위한 베이스 케이스
int sum_all() { return 0; }
template <typename... Ints>
int sum_all(int num, Ints... nums) {
return num + sum_all(nums...);
}
template <typename... Ints>
double average(Ints... nums) {
return static_cast<double>(sum_all(nums...)) / sizeof...(nums);
}
int main() {
// (1 + 4 + 2 + 3 + 10) / 5
std::cout << average(1, 4, 2, 3, 10) << std::endl;
}
sizeof는 인자의 크기를 리턴
size of... 는 인자의 개수를 리턴
Fold Expression
C++11에서 도입된 가변 길이 템플릿은 매우 편리하지만 재귀 함수 형태로 구성해야 하기 때문에, 반드시 재귀 호출 종료를 위한 함수를 따로 만들어야 한다.
// 재귀 호출 종료를 위한 베이스 케이스
int sum_all() { return 0; }
이것처럼.
하지만 C++17에 새로 도입된 Fold 형식을 사용한다면 이를 훨씬 간단하게 표현할 수 있다.
#include <iostream>
template <typename... Ints>
int sum_all(Ints... nums) {
return (... + nums); // 이렇게!
}
int main() {
// 1 + 4 + 2 + 3 + 10
std::cout << sum_all(1, 4, 2, 3, 10) << std::endl;
}
코드를 보면
return (... + nums); // 단항 좌측 Fold (Unary left fold)
위와 같은 부분을 컴파일러에서는 아래와 같이 해석한다.
return ((((1 + 4) + 2) + 3) + 10);
다양한 Fold 방식
,
연산자를 이용하여 각각의 인자들에 대해 원하는 식을 실행할 수 있다.
#include <iostream>
class A {
public:
void do_something(int x) const {
std::cout << "Do something with " << x << std::endl;
}
};
template <typename T, typename... Ints>
void do_many_things(const T& t, Ints... nums) {
// 각각의 인자들에 대해 do_something 함수들을 호출한다.
(t.do_something(nums), ...);
}
int main() {
A a;
do_many_things(a, 1, 3, 2, 4);
}
9-3. 템플릿 메타 프로그래밍 (Template Meta programming)
타입을 가지고 컴파일 타임에 생성되는 코드로 프로그래밍을 하는 것을 메타 프로그래밍(meta programming) 이라고 한다. C++ 의 경우 템플릿을 가지고 이러한 작업을 하기 때문에 템플릿 메타 프로그래밍, 줄여서 TMP 라고 부른다.
TMP 를 이용하는 경우는 꽤나 제한적이지만, 많은 C++ 라이브러리들이 TMP 를 이용해서 구현되었다 (Boost 라이브러리). TMP 를 통해서 컴파일 타임에 여러 오류들을 잡아낼 수 도 있고 (Ex. 단위나 통화 일치 여부등등) 속도가 매우 중요한 프로그램의 경우 TMP 를 통해서 런타임 속도도 향상 시킬 수 있다.
팩토리얼 계산
#include <iostream>
#include <typeinfo>
template <int N>
struct Int {
static const int num = N;
};
template <typename T, typename U>
struct add {
typedef Int<T::num + U::num> result;
};
int main() {
typedef Int<1> one; //타입 생성
typedef Int<2> two;
typedef add<one, two>::result three;
std::cout << "Addtion result : " << three::num << std::endl;
}
최대 공약수 구하기
- 일반적인 함수
int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}
- TMP
#include <iostream>
template <int X, int Y>
struct GCD {
static const int value = GCD<Y, X % Y>::value;
};
template <int X>
struct GCD<X, 0> {
static const int value = X;
};
int main() {
std::cout << "gcd (36, 24) :: " << GCD<36, 24>::value << std::endl;
}
Ratio : 유리수를 오차없이 표현해 주는 클래스
#include <iostream>
#include <typeinfo>
template <int X, int Y>
struct GCD {
static const int value = GCD<Y, X % Y>::value;
};
template <int X>
struct GCD<X, 0> {
static const int value = X;
};
template <int N, int D = 1>
struct Ratio {
typedef Ratio<N, D> type;
static const int num = N; // 분자
static const int den = D; // 분모
};
template <class R1, class R2>
struct _Ratio_add {
typedef Ratio<R1::num * R2::den + R2::num * R1::den, R1::den * R2::den> type;
};
template <class R1, class R2>
struct Ratio_add : _Ratio_add<R1, R2>::type {};
int main() {
typedef Ratio<2, 3> rat;
typedef Ratio<3, 2> rat2;
typedef Ratio_add<rat, rat2> rat3;
std::cout << rat3::num << " / " << rat3::den << std::endl;
return 0;
}
C++11 부터 typedef 대신에 좀 더 직관적인 using 이라는 키워드를 사용할 수 있다.
typedef Ratio_add<rat, rat2> rat3;
using rat3 = Ratio_add<rat, rat2>;
생각해보기- 문제1
N 번째 피보나치 수를 나타내는 TMP 를 만들어보세요. 참고로 피보나치 수는, N 번째 항이 N - 1 번째 항과 N - 2 번째 항의 합으로 정의되는 수 입니다. 참고로 1, 1, 2, 3, 5, ... 로 진행됩니다.(난이도 : 하)
#include <iostream>
template <int N>
struct fib {
static const int result = fib<N-1>::result + fib<N-2>::result;
};
template <>
struct fib<1> {
static const int result = 1;
};
template <>
struct fib<2> {
static const int result = 1;
};
9-4. 템플릿 메타 프로그래밍 2 (Template Meta programming 2)
단위 라이브러리
Dim 구조체를 이용하여 단위 별로 계산할 수 있는 프로그램을 만들어본다.
#include <iostream>
template <int X, int Y>
struct GCD { //최대 공약수
static const int value = GCD<Y, X% Y>::value;
};
template <int X>
struct GCD<X, 0> {
static const int value = X;
};
template <int N, int D =1 >
struct Ratio {
private:
const static int _gcd = GCD<N, D>::value;
public:
typedef Ratio<N / _gcd, D / _gcd> type;
static const int num = N / _gcd;
static const int den = D / _gcd;
};
template<class R1, class R2>
struct _Ratio_add {
using type = Ratio<R1::num* R2::den + R2::num * R1::den, R1::den* R2::den>;
};
template<class R1, class R2>
struct Ratio_add: _Ratio_add<R1,R2>::type{};
template <class R1, class R2>
struct _Ratio_subtract {
using type = Ratio<R1::num* R2::den - R2::num * R1::den, R1::den* R2::den>;
};
template <class R1, class R2>
struct Ratio_subtract : _Ratio_subtract<R1, R2>::type {};
template <class R1, class R2>
struct _Ratio_multiply {
using type = Ratio<R1::num* R2::num, R1::den* R2::den>;
};
template <class R1, class R2>
struct Ratio_multiply : _Ratio_multiply<R1, R2>::type {};
template <class R1, class R2>
struct _Ratio_divide {
using type = Ratio<R1::num* R2::den, R1::den* R2::num>;
};
template <class R1, class R2>
struct Ratio_divide : _Ratio_divide<R1, R2>::type {};
template <typename U, typename V, typename W>
struct Dim {
using M = U;
using L = V;
using T = W;
using type = Dim<M, L, T>;
};
template <typename U, typename V>
struct add_dim_ {
typedef Dim<typename Ratio_add<typename U::M, typename V::M>::type,
typename Ratio_add<typename U::L, typename V::L>::type,
typename Ratio_add<typename U::T, typename V::T>::type>
type;
};
template <typename U, typename V>
struct subtract_dim_ {
typedef Dim<typename Ratio_subtract<typename U::M, typename V::M>::type,
typename Ratio_subtract<typename U::L, typename V::L>::type,
typename Ratio_subtract<typename U::T, typename V::T>::type>
type;
};
template <typename T, typename D>
struct quantity {
T q;
using dim_type = D;
quantity operator+ (quantity<T, D> quant) {
return quantity<T, D>(q + quant.q);
}
quantity(T q): q(q){}
};
int main() {
using one = Ratio<1, 1>;
using zero = Ratio<0, 1>;
quantity<double, Dim<one, zero, zero>> kg(1);
quantity<double, Dim<zero, one, zero>> meter(1);
quantity<double, Dim<zero, zero, one>> second(1);
// Good
kg + kg;
//Bad
//kg + meter;
}
이번꺼 너무 어렵다....
- typename
struct check_div<N, typename divide<N, two>::result> {
타입/ 값 중에 어떤 것에 속하는지를 명시해주어야 하는데, 위와 같이 타입 형식에는 typename을 적어준다.
check_div는 값이라서 적어줄 필요 없음
- */ operator
template <typename D2>
quantity<T, typename add_dim_<D, D2>::type> operator*(quantity<T, D2> quant) {
return quantity<T, typename add_dim_<D, D2>::type>(q * quant.q);
}
template <typename D2>
quantity<T, typename subtract_dim_<D, D2>::type> operator/(
quantity<T, D2> quant) {
return quantity<T, typename subtract_dim_<D, D2>::type>(q / quant.q);
}
quantity<T, D> operator*(T scalar) { return quantity<T, D>(q * scalar); }
quantity<T, D> operator/(T scalar) { return quantity<T, D>(q / scalar); }
Auto
컴파일러가 타입을 정확히 알아낼 수 있는 경우 굳이 그 길고 긴 타입을 적지 않고 간단히 auto 로 표현할 수 있다. (컴파일 시에 컴파일러가 추론)
auto c = sum(1, 2); // 함수 리턴 타입으로 부터 int 라고 추측 가능
auto num = 1.0 + 2.0; // double 로 추측 가능!
auto some3(10); // SomeClass 객체를 만들까요? ---> NO, int 정수형으로 만든다
auto F = kg * meter / (second * second); // F 의 타입 추론 가능 (리턴 타입)
- 전체 코드
#include <iostream>
#include <typeinfo>
template <int X, int Y>
struct GCD {
static const int value = GCD<Y, X % Y>::value;
};
template <int X>
struct GCD<X, 0> {
static const int value = X;
};
template <int N, int D = 1>
struct Ratio {
private:
const static int _gcd = GCD<N, D>::value;
public:
typedef Ratio<N / _gcd, D / _gcd> type;
static const int num = N / _gcd;
static const int den = D / _gcd;
};
template <class R1, class R2>
struct _Ratio_add {
using type = Ratio<R1::num * R2::den + R2::num * R1::den, R1::den * R2::den>;
};
template <class R1, class R2>
struct Ratio_add : _Ratio_add<R1, R2>::type {};
template <class R1, class R2>
struct _Ratio_subtract {
using type = Ratio<R1::num * R2::den - R2::num * R1::den, R1::den * R2::den>;
};
template <class R1, class R2>
struct Ratio_subtract : _Ratio_subtract<R1, R2>::type {};
template <class R1, class R2>
struct _Ratio_multiply {
using type = Ratio<R1::num * R2::num, R1::den * R2::den>;
};
template <class R1, class R2>
struct Ratio_multiply : _Ratio_multiply<R1, R2>::type {};
template <class R1, class R2>
struct _Ratio_divide {
using type = Ratio<R1::num * R2::den, R1::den * R2::num>;
};
template <class R1, class R2>
struct Ratio_divide : _Ratio_divide<R1, R2>::type {};
template <typename U, typename V, typename W>
struct Dim {
using M = U;
using L = V;
using T = W;
using type = Dim<M, L, T>;
};
template <typename U, typename V>
struct add_dim_ {
typedef Dim<typename Ratio_add<typename U::M, typename V::M>::type,
typename Ratio_add<typename U::L, typename V::L>::type,
typename Ratio_add<typename U::T, typename V::T>::type>
type;
};
template <typename U, typename V>
struct subtract_dim_ {
typedef Dim<typename Ratio_subtract<typename U::M, typename V::M>::type,
typename Ratio_subtract<typename U::L, typename V::L>::type,
typename Ratio_subtract<typename U::T, typename V::T>::type>
type;
};
template <typename T, typename D>
struct quantity {
T q;
using dim_type = D;
quantity operator+(quantity<T, D> quant) {
return quantity<T, D>(q + quant.q);
}
quantity operator-(quantity<T, D> quant) {
return quantity<T, D>(q - quant.q);
}
template <typename D2>
quantity<T, typename add_dim_<D, D2>::type> operator*(quantity<T, D2> quant) {
return quantity<T, typename add_dim_<D, D2>::type>(q * quant.q);
}
template <typename D2>
quantity<T, typename subtract_dim_<D, D2>::type> operator/(
quantity<T, D2> quant) {
return quantity<T, typename subtract_dim_<D, D2>::type>(q / quant.q);
}
// Scalar multiplication and division
quantity<T, D> operator*(T scalar) { return quantity<T, D>(q * scalar); }
quantity<T, D> operator/(T scalar) { return quantity<T, D>(q / scalar); }
quantity(T q) : q(q) {}
};
template <typename T, typename D>
std::ostream& operator<<(std::ostream& out, const quantity<T, D>& q) {
out << q.q << "kg^" << D::M::num / D::M::den << "m^" << D::L::num / D::L::den
<< "s^" << D::T::num / D::T::den;
return out;
}
int main() {
using one = Ratio<1, 1>;
using zero = Ratio<0, 1>;
quantity<double, Dim<one, zero, zero>> kg(2);
quantity<double, Dim<zero, one, zero>> meter(3);
quantity<double, Dim<zero, zero, one>> second(1);
// F 의 타입은 굳이 알필요 없다!
auto F = kg * meter / (second * second);
std::cout << "2 kg 물체를 3m/s^2 의 가속도로 밀기 위한 힘의 크기는? " << F
<< std::endl;
}
'개발 > C++' 카테고리의 다른 글
[ 씹어먹는 C++ ] C++에서의 예외 처리 (2) | 2024.09.08 |
---|---|
[ 씹어먹는 C++ ] 10. C++ STL (3) | 2024.09.01 |
씹어먹는 C++ 공부하기 (0) | 2024.05.16 |
[OS/ C++] 동기화를 위한 전략: 스핀락(spinlick), 뮤택스(mutex), 세마포(semaphore) (0) | 2024.02.08 |
힙(Heap)과 스택(Stack)과 메모리 할당과 해제 (1) | 2024.02.05 |